﻿using System;
using l1cs.server.datatables;
using l1cs.server.serverpackets;
using l1cs.server.model.skill;
using l1cs.server.utils;
using l1cs.server.templates;
using System.Collections.Generic;
using l1cs.server.command.executor;
using l1cs.server.model.classes;
using l1cs.server.model.gametime;
using System.Threading;
using l1cs.server.model.monitor;
using System.Collections;
using System.Diagnostics;

namespace l1cs.server.model.Instance
{
    public class L1PcInstance : L1Character
    {
        public const int CLASSID_KNIGHT_MALE = 61;
        public const int CLASSID_KNIGHT_FEMALE = 48;
        public const int CLASSID_ELF_MALE = 138;
        public const int CLASSID_ELF_FEMALE = 37;
        public const int CLASSID_WIZARD_MALE = 734;
        public const int CLASSID_WIZARD_FEMALE = 1186;
        public const int CLASSID_DARK_ELF_MALE = 2786;
        public const int CLASSID_DARK_ELF_FEMALE = 2796;
        public const int CLASSID_PRINCE = 0;
        public const int CLASSID_PRINCESS = 1;
        public const int CLASSID_DRAGON_KNIGHT_MALE = 6658;
        public const int CLASSID_DRAGON_KNIGHT_FEMALE = 6661;
        public const int CLASSID_ILLUSIONIST_MALE = 6671;
        public const int CLASSID_ILLUSIONIST_FEMALE = 6650;

        private static Random _random = new Random();

        private short _hpr = 0;
        private short _trueHpr = 0;

        public short getHpr()
        {
            return _hpr;
        }

        public void addHpr( int i )
        {
            _trueHpr += (short)i;
            _hpr = (short)Math.Max( 0, (int)_trueHpr );
        }

        private short _mpr = 0;
        private short _trueMpr = 0;

        public short getMpr()
        {
            return _mpr;
        }

        public void addMpr( int i )
        {
            _trueMpr += (short)i;
            _mpr = (short)Math.Max( 0, (int)_trueMpr );
        }

        /// <summary>
        /// オリジナルCON HPR
        /// </summary>
        public short _originalHpr = 0;

        public short getOriginalHpr()
        {

            return _originalHpr;
        }

        /// <summary>
        /// オリジナルWIS MPR
        /// </summary>
        public short _originalMpr = 0;

        public short getOriginalMpr()
        {

            return _originalMpr;
        }

        public void startHpRegeneration()
        {
            int INTERVAL = 1000;

            if ( !_hpRegenActive )
            {
                _hpRegen = new HpRegeneration( this );
                // TODO 優先度9 タイマースレッド
                //_regenTimer.scheduleAtFixedRate( _hpRegen, INTERVAL, INTERVAL );
                _regenTimer = new Timer( new TimerCallback( _hpRegen.run ), null, INTERVAL, INTERVAL );
                _hpRegenActive = true;
            }
        }

        public void stopHpRegeneration()
        {
            if ( _hpRegenActive )
            {
                _hpRegen.cancel();
                _hpRegen = null;
                _hpRegenActive = false;
            }
        }

        public void startMpRegeneration()
        {
            int INTERVAL = 1000;

            if ( !_mpRegenActive )
            {
                _mpRegen = new MpRegeneration( this );
                // TODO 優先度9 タイマースレッド
                //_regenTimer.scheduleAtFixedRate( _mpRegen, INTERVAL, INTERVAL );
                _regenTimer = new Timer( new TimerCallback( _mpRegen.run ), null, INTERVAL, INTERVAL );
                _mpRegenActive = true;
            }
        }

        public void startMpRegenerationByDoll()
        {
            int INTERVAL_BY_DOLL = 60000;
            bool isExistMprDoll = false;
            foreach ( L1DollInstance doll in getDollList().Values )
            {
                if ( doll.isMpRegeneration() )
                {
                    isExistMprDoll = true;
                }
            }
            if ( !_mpRegenActiveByDoll && isExistMprDoll )
            {
                _mpRegenByDoll = new MpRegenerationByDoll( this );
                // TODO 優先度9 スレッドタイマー
                //_regenTimer.scheduleAtFixedRate(_mpRegenByDoll, INTERVAL_BY_DOLL, INTERVAL_BY_DOLL);
                _regenTimer = new Timer( new TimerCallback( _mpRegenByDoll.run ), null, INTERVAL_BY_DOLL, INTERVAL_BY_DOLL );
                _mpRegenActiveByDoll = true;
            }
        }

        public void startMpReductionByAwake()
        {
            const int INTERVAL_BY_AWAKE = 4000;
            if ( !_mpReductionActiveByAwake )
            {
                _mpReductionByAwake = new MpReductionByAwake( this );
                // TODO 優先度9 スレッドタイマー
                //_regenTimer.scheduleAtFixedRate(_mpReductionByAwake, INTERVAL_BY_AWAKE, INTERVAL_BY_AWAKE);
                _regenTimer = new Timer( new TimerCallback( _mpReductionByAwake.run ), null, INTERVAL_BY_AWAKE, INTERVAL_BY_AWAKE );
                _mpReductionActiveByAwake = true;
            }
        }

        public void stopMpRegeneration()
        {
            if ( _mpRegenActive )
            {
                _mpRegen.cancel();
                _mpRegen = null;
                _mpRegenActive = false;
            }
        }

        public void stopMpRegenerationByDoll()
        {
            if ( _mpRegenActiveByDoll )
            {
                _mpRegenByDoll.cancel();
                _mpRegenByDoll = null;
                _mpRegenActiveByDoll = false;
            }
        }

        public void stopMpReductionByAwake()
        {
            if ( _mpReductionActiveByAwake )
            {
                _mpReductionByAwake.cancel();
                _mpReductionByAwake = null;
                _mpReductionActiveByAwake = false;
            }
        }

        public void startObjectAutoUpdate()
        {
            removeAllKnownObjects();
            // TODO 優先度9 タイマースレッド
            //_autoUpdateFuture = GeneralThreadPool.getInstance().pcScheduleAtFixedRate( new L1PcAutoUpdate getId() ), 0L, INTERVAL_AUTO_UPDATE );
            L1PcAutoUpdate pau = new L1PcAutoUpdate( getId() );
            _autoUpdateFuture = new Timer( new TimerCallback( pau.run ), null, 0, INTERVAL_AUTO_UPDATE );
        }

        /**
         * 各種モニタータスクを停止する。
         */
        public void stopEtcMonitor()
        {
            if ( _autoUpdateFuture != null )
            {
                _autoUpdateFuture.Dispose();
                _autoUpdateFuture = null;
            }
            if ( _expMonitorFuture != null )
            {
                _expMonitorFuture.Dispose();
                _expMonitorFuture = null;
            }
            if ( _ghostFuture != null )
            {
                _ghostFuture.Dispose();
                _ghostFuture = null;
            }

            if ( _hellFuture != null )
            {
                _hellFuture.Dispose();
                _hellFuture = null;
            }
        }

        private const long INTERVAL_AUTO_UPDATE = 300;
        private Timer _autoUpdateFuture;

        private const int INTERVAL_EXP_MONITOR = 500;
        private Timer _expMonitorFuture;

        public void onChangeExp()
        {
            int level = ExpTable.getLevelByExp( getExp() );
            int char_level = getLevel();
            int gap = level - char_level;
            if ( gap == 0 )
            {
                // sendPackets(new S_OwnCharStatus(this));
                sendPackets( new S_Exp( this ) );
                return;
            }

            // レベルが変化した場合
            if ( gap > 0 )
            {
                levelUp( gap );
            }
            else if ( gap < 0 )
            {
                levelDown( gap );
            }
        }

        public override void onPerceive( L1PcInstance perceivedFrom )
        {
            if ( isGmInvis() || isGhost() )
            {
                return;
            }
            if ( isInvisble() && !perceivedFrom.hasSkillEffect( L1SkillId.GMSTATUS_FINDINVIS ) )
            {
                return;
            }

            perceivedFrom.addKnownObject( this );
            perceivedFrom.sendPackets( new S_OtherCharPacks( this,
                    perceivedFrom.hasSkillEffect( L1SkillId.GMSTATUS_FINDINVIS ) ) ); // 自分の情報を送る
            if ( isInParty() && getParty().isMember( perceivedFrom ) )
            { // PTメンバーならHPメーターも送る
                perceivedFrom.sendPackets( new S_HPMeter( this ) );
            }

            if ( isPrivateShop() )
            {
                perceivedFrom.sendPackets( new S_DoActionShop( getId(),
                        ActionCodes.ACTION_Shop, getShopChat() ) );
            }

            if ( isCrown() )
            { // 君主
                L1Clan clan = L1World.getInstance().getClan( getClanname() );
                if ( clan != null )
                {
                    if ( getId() == clan.getLeaderId() // 血盟主で城主クラン
                            && clan.getCastleId() != 0 )
                    {
                        perceivedFrom.sendPackets( new S_CastleMaster( clan
                                .getCastleId(), getId() ) );
                    }
                }
            }
        }

        // 範囲外になった認識済みオブジェクトを除去
        private void removeOutOfRangeObjects()
        {
            foreach ( L1Object known in getKnownObjects() )
            {
                if ( known == null )
                {
                    continue;
                }

                if ( Config.PC_RECOGNIZE_RANGE == -1 )
                {
                    if ( !getLocation().isInScreen( known.getLocation() ) )
                    { // 画面外
                        removeKnownObject( known );
                        sendPackets( new S_RemoveObject( known ) );
                    }
                }
                else
                {
                    if ( getLocation().getTileLineDistance( known.getLocation() ) > Config.PC_RECOGNIZE_RANGE )
                    {
                        removeKnownObject( known );
                        sendPackets( new S_RemoveObject( known ) );
                    }
                }
            }
        }

        /// <summary>
        ///  オブジェクト認識処理
        /// </summary>
        public void updateObject()
        {
            removeOutOfRangeObjects();

            // 認識範囲内のオブジェクトリストを作成
            foreach ( L1Object visible in L1World.getInstance().getVisibleObjects( this,
                    Config.PC_RECOGNIZE_RANGE ) )
            {
                if ( !knownsObject( visible ) )
                {
                    visible.onPerceive( this );
                }
                else
                {
                    if ( visible is L1NpcInstance )
                    {
                        L1NpcInstance npc = (L1NpcInstance)visible;
                        if ( getLocation().isInScreen( npc.getLocation() ) && npc.getHiddenStatus() != 0 )
                        {
                            npc.approachPlayer( this );
                        }
                    }
                }
                if ( hasSkillEffect( L1SkillId.GMSTATUS_HPBAR )
                        && L1HpBar.isHpBarTarget( visible ) )
                {
                    sendPackets( new S_HPMeter( (L1Character)visible ) );
                }
            }
        }

        private void sendVisualEffect()
        {
            int poisonId = 0;
            if ( getPoison() != null )
            { // 毒状態
                poisonId = getPoison().getEffectId();
            }
            if ( getParalysis() != null )
            { // 麻痺状態
                // 麻痺エフェクトを優先して送りたい為、poisonIdを上書き。
                poisonId = getParalysis().getEffectId();
            }
            if ( poisonId != 0 )
            { // このifはいらないかもしれない
                sendPackets( new S_Poison( getId(), poisonId ) );
                broadcastPacket( new S_Poison( getId(), poisonId ) );
            }
        }

        public void sendVisualEffectAtLogin()
        {
            // S_Emblemの送信はC_Clanに移行
            // for (L1Clan clan : L1World.getInstance().getAllClans()) {
            // sendPackets(new S_Emblem(clan.getClanId()));
            // }

            if ( getClanid() != 0 )
            { // クラン所属
                L1Clan clan = L1World.getInstance().getClan( getClanname() );
                if ( clan != null )
                {
                    if ( isCrown() && getId() == clan.getLeaderId() && // プリンスまたはプリンセス、かつ、血盟主で自クランが城主
                            clan.getCastleId() != 0 )
                    {
                        sendPackets( new S_CastleMaster( clan.getCastleId(), getId() ) );
                    }
                }
            }

            sendVisualEffect();
        }

        public void sendVisualEffectAtTeleport()
        {
            if ( isDrink() )
            {
                // liquorで酔っている
                sendPackets( new S_Liquor( getId() ) );
            }

            sendVisualEffect();
        }

        private List<int> skillList = new List<int>();

        public void setSkillMastery( int skillid )
        {
            if ( !skillList.Contains( skillid ) )
            {
                skillList.Add( skillid );
            }
        }

        public void removeSkillMastery( int skillid )
        {
            if ( skillList.Contains( skillid ) )
            {
                skillList.Remove( skillid );
            }
        }

        public bool isSkillMastery( int skillid )
        {
            return skillList.Contains( skillid );
        }

        public void clearSkillMastery()
        {
            skillList.Clear();
        }

        public L1PcInstance()
        {
            _accessLevel = 0;
            _currentWeapon = 0;
            _inventory = new L1PcInventory( this );
            _dwarf = new L1DwarfInventory( this );
            _dwarfForElf = new L1DwarfForElfInventory( this );
            _tradewindow = new L1Inventory();
            _bookmarks = new List<L1BookMark>();
            _quest = new L1Quest( this );
            _equipSlot = new L1EquipmentSlot( this ); // コンストラクタでthisポインタを渡すのは安全だろうか・・・
        }

        override public void setCurrentHp( int i )
        {
            if ( getCurrentHp() == i )
            {
                return;
            }
            int currentHp = i;
            if ( currentHp >= getMaxHp() )
            {
                currentHp = getMaxHp();
            }
            setCurrentHpDirect( currentHp );
            sendPackets( new S_HPUpdate( currentHp, getMaxHp() ) );
            if ( isInParty() )
            { // パーティー中
                getParty().updateMiniHP( this );
            }
        }

        override public void setCurrentMp( int i )
        {
            if ( getCurrentMp() == i )
            {
                return;
            }
            int currentMp = i;
            if ( currentMp >= getMaxMp() || isGm() )
            {
                currentMp = getMaxMp();
            }
            setCurrentMpDirect( currentMp );
            sendPackets( new S_MPUpdate( currentMp, getMaxMp() ) );
        }

        /// <summary>
        /// インベントリインスタンスを取得する。
        /// </summary>
        /// <returns>インベントリインスタンス</returns>
        override public L1PcInventory getInventory()
        {
            return _inventory;
        }

        public L1DwarfInventory getDwarfInventory()
        {
            return _dwarf;
        }

        public L1DwarfForElfInventory getDwarfForElfInventory()
        {
            return _dwarfForElf;
        }

        public L1Inventory getTradeWindowInventory()
        {
            return _tradewindow;
        }

        public bool isGmInvis()
        {
            return _gmInvis;
        }

        public void setGmInvis( bool flag )
        {
            _gmInvis = flag;
        }

        public int getCurrentWeapon()
        {
            return _currentWeapon;
        }

        public void setCurrentWeapon( int i )
        {
            _currentWeapon = i;
        }

        public int getType()
        {
            return _type;
        }

        public void setType( int i )
        {
            _type = i;
        }

        public short getAccessLevel()
        {
            return _accessLevel;
        }

        public void setAccessLevel( short i )
        {
            _accessLevel = i;
        }

        public int getClassId()
        {
            return _classId;
        }

        public void setClassId( int i )
        {
            _classId = i;
            _classFeature = L1ClassFeature.newClassFeature( i );
        }

        private L1ClassFeature _classFeature = null;

        public L1ClassFeature getClassFeature()
        {
            return _classFeature;
        }

        override public int getExp()
        {
            lock ( this )
            {
                return _exp;
            }
        }

        override public void setExp( int i )
        {
            lock ( this )
            {
                _exp = i;
            }
        }

        /// <summary>
        /// PKカウント
        /// </summary>
        private int _PKcount;

        public int get_PKcount()
        {
            return _PKcount;
        }

        public void set_PKcount( int i )
        {
            _PKcount = i;
        }

        /// <summary>
        /// PKカウント(エルフ用)
        /// </summary>
        private int _PkCountForElf;

        public int getPkCountForElf()
        {
            return _PkCountForElf;
        }

        public void setPkCountForElf( int i )
        {
            _PkCountForElf = i;
        }

        /// <summary>
        /// クランＩＤ
        /// </summary>
        private int _clanid;

        public int getClanid()
        {
            return _clanid;
        }

        public void setClanid( int i )
        {
            _clanid = i;
        }

        /// <summary>
        /// クラン名
        /// </summary>
        private String clanname;

        public String getClanname()
        {
            return clanname;
        }

        public void setClanname( String s )
        {
            clanname = s;
        }

        // 参照を持つようにしたほうがいいかもしれない
        public L1Clan getClan()
        {
            return L1World.getInstance().getClan( getClanname() );
        }

        /// <summary>
        /// クラン内のランク(血盟君主、ガーディアン、一般、見習い)
        /// </summary>
        private int _clanRank;

        public int getClanRank()
        {
            return _clanRank;
        }

        public void setClanRank( int i )
        {
            _clanRank = i;
        }

        /// <summary>
        /// 性別
        /// </summary>
        private byte _sex;

        public byte get_sex()
        {
            return _sex;
        }

        public void set_sex( int i )
        {
            _sex = (byte)i;
        }

        public bool isGm()
        {
            return _gm;
        }

        public void setGm( bool flag )
        {
            _gm = flag;
        }

        public bool isMonitor()
        {
            return _monitor;
        }

        public void setMonitor( bool flag )
        {
            _monitor = flag;
        }

        private L1PcInstance getStat()
        {
            return null;
        }

        public void reduceCurrentHp( double d, L1Character l1character )
        {
            getStat().reduceCurrentHp( d, l1character );
        }

        /// <summary>
        /// 指定されたプレイヤー群にログアウトしたことを通知する。
        /// </summary>
        /// <param name="playersArray">通知するプレイヤーの配列</param>
        private void notifyPlayersLogout( ArrayList playersArray )
        {
            foreach ( L1PcInstance player in playersArray )
            {
                if ( player.knownsObject( this ) )
                {
                    player.removeKnownObject( this );
                    player.sendPackets( new S_RemoveObject( this ) );
                }
            }
        }
        /// <summary>
        /// TODO 優先度3 ArrayListからListにする方法が分からないので二重定義
        /// </summary>
        /// <param name="playersArray"></param>
        private void notifyPlayersLogout( List<L1PcInstance> playersArray )
        {
            foreach ( L1PcInstance player in playersArray )
            {
                if ( player.knownsObject( this ) )
                {
                    player.removeKnownObject( this );
                    player.sendPackets( new S_RemoveObject( this ) );
                }
            }
        }

        public void logout()
        {
            L1World world = L1World.getInstance();
            if ( getClanid() != 0 ) // クラン所属
            {
                L1Clan clan = world.getClan( getClanname() );
                if ( clan != null )
                {
                    if ( clan.getWarehouseUsingChar() == getId() ) // 自キャラがクラン倉庫使用中
                    {
                        clan.setWarehouseUsingChar( 0 ); // クラン倉庫のロックを解除
                    }
                }
            }
            notifyPlayersLogout( getKnownPlayers() );
            world.removeVisibleObject( this );
            world.removeObject( this );
            notifyPlayersLogout( world.getRecognizePlayer( this ) );
            _inventory.clearItems();
            _dwarf.clearItems();
            removeAllKnownObjects();
            stopHpRegeneration();
            stopMpRegeneration();
            setDead( true ); // 使い方おかしいかもしれないけど、ＮＰＣに消滅したことをわからせるため
            setNetConnection( null );
            setPacketOutput( null );
        }

        /// <summary>
        /// 接続状態を返す。
        /// </summary>
        /// <returns></returns>
        public ClientThread getNetConnection()
        {
            return _netConnection;
        }

        /// <summary>
        /// 接続状態を設定する。
        /// </summary>
        /// <param name="clientthread"></param>
        public void setNetConnection( ClientThread clientthread )
        {
            _netConnection = clientthread;
        }

        public bool isInParty()
        {
            return getParty() != null;
        }

        public L1Party getParty()
        {
            return _party;
        }

        public void setParty( L1Party p )
        {
            _party = p;
        }

        public bool isInChatParty()
        {
            return getChatParty() != null;
        }

        public L1ChatParty getChatParty()
        {
            return _chatParty;
        }

        public void setChatParty( L1ChatParty cp )
        {
            _chatParty = cp;
        }

        public int getPartyID()
        {
            return _partyID;
        }

        public void setPartyID( int partyID )
        {
            _partyID = partyID;
        }

        public int getTradeID()
        {
            return _tradeID;
        }

        public void setTradeID( int tradeID )
        {
            _tradeID = tradeID;
        }

        public void setTradeOk( bool tradeOk )
        {
            _tradeOk = tradeOk;
        }

        public bool getTradeOk()
        {
            return _tradeOk;
        }

        public int getTempID()
        {
            return _tempID;
        }

        public void setTempID( int tempID )
        {
            _tempID = tempID;
        }

        public bool isTeleport()
        {
            return _isTeleport;
        }

        public void setTeleport( bool flag )
        {
            _isTeleport = flag;
        }

        public bool isDrink()
        {
            return _isDrink;
        }

        public void setDrink( bool flag )
        {
            _isDrink = flag;
        }

        public bool isGres()
        {
            return _isGres;
        }

        public void setGres( bool flag )
        {
            _isGres = flag;
        }

        public bool isPinkName()
        {
            return _isPinkName;
        }

        public void setPinkName( bool flag )
        {
            _isPinkName = flag;
        }

        private List<L1PrivateShopSellList> _sellList = new List<L1PrivateShopSellList>();

        public List<L1PrivateShopSellList> getSellList()
        {
            return _sellList;
        }

        private List<L1PrivateShopBuyList> _buyList = new List<L1PrivateShopBuyList>();

        public List<L1PrivateShopBuyList> getBuyList()
        {
            return _buyList;
        }

        private byte[] _shopChat;

        public void setShopChat( byte[] chat )
        {
            _shopChat = chat;
        }

        public byte[] getShopChat()
        {
            return _shopChat;
        }

        private bool _isPrivateShop = false;

        public bool isPrivateShop()
        {
            return _isPrivateShop;
        }

        public void setPrivateShop( bool flag )
        {
            _isPrivateShop = flag;
        }

        private bool _isTradingInPrivateShop = false;

        public bool isTradingInPrivateShop()
        {
            return _isTradingInPrivateShop;
        }

        public void setTradingInPrivateShop( bool flag )
        {
            _isTradingInPrivateShop = flag;
        }

        private int _partnersPrivateShopItemCount = 0; // 閲覧中の個人商店のアイテム数

        public int getPartnersPrivateShopItemCount()
        {
            return _partnersPrivateShopItemCount;
        }

        public void setPartnersPrivateShopItemCount( int i )
        {
            _partnersPrivateShopItemCount = i;
        }

        private PacketOutput _out;

        /// <summary>
        /// パケット出力クラスを設定する。
        /// </summary>
        /// <param name="l1out"></param>
        public void setPacketOutput( PacketOutput l1out )
        {
            _out = l1out;
        }

        /// <summary>
        /// パケットを送信する。
        /// </summary>
        /// <param name="serverbasepacket"></param>
        public void sendPackets( ServerBasePacket serverbasepacket )
        {
            if ( _out == null )
            {
                _log.info( "_out is null" );
                return;
            }
            _log.info( "sendpacket[" + serverbasepacket.getType() + "]" );
            _out.sendPacket( serverbasepacket );

        }

        override public void onAction( L1PcInstance attacker )
        {
            // XXX:NullPointerException回避。onActionの引数の型はL1Characterのほうが良い？
            if ( attacker == null )
            {
                return;
            }
            // テレポート処理中
            if ( isTeleport() )
            {
                return;
            }
            // 攻撃される側または攻撃する側がセーフティーゾーン
            if ( getZoneType() == 1 || attacker.getZoneType() == 1 )
            {
                // 攻撃モーション送信
                L1Attack attack_mortion = new L1Attack( attacker, this );
                attack_mortion.action();
                return;
            }

            if ( checkNonPvP( this, attacker ) == true )
            {
                // 攻撃モーション送信
                L1Attack attack_mortion = new L1Attack( attacker, this );
                attack_mortion.action();
                return;
            }

            if ( getCurrentHp() > 0 && !isDead() )
            {
                attacker.delInvis();

                bool isCounterBarrier = false;
                L1Attack attack = new L1Attack( attacker, this );
                if ( attack.calcHit() )
                {
                    if ( hasSkillEffect( L1SkillId.COUNTER_BARRIER ) )
                    {
                        L1Magic magic = new L1Magic( this, attacker );
                        bool isProbability = magic
                                .calcProbabilityMagic( L1SkillId.COUNTER_BARRIER );
                        bool isShortDistance = attack.isShortDistance();
                        if ( isProbability && isShortDistance )
                        {
                            isCounterBarrier = true;
                        }
                    }
                    if ( !isCounterBarrier )
                    {
                        attacker.setPetTarget( this );

                        attack.calcDamage();
                        attack.calcStaffOfMana();
                        attack.addPcPoisonAttack( attacker, this );
                        attack.addChaserAttack();
                    }
                }
                if ( isCounterBarrier )
                {
                    attack.actionCounterBarrier();
                    attack.commitCounterBarrier();
                }
                else
                {
                    attack.action();
                    attack.commit();
                }
            }
        }

        public bool checkNonPvP( L1PcInstance pc, L1Character target )
        {
            L1PcInstance targetpc = null;
            if ( target is L1PcInstance )
            {
                targetpc = (L1PcInstance)target;
            }
            else if ( target is L1PetInstance )
            {
                targetpc = (L1PcInstance)( (L1PetInstance)target ).getMaster();
            }
            else if ( target is L1SummonInstance )
            {
                targetpc = (L1PcInstance)( (L1SummonInstance)target ).getMaster();
            }
            if ( targetpc == null )
            {
                return false; // 相手がPC、サモン、ペット以外
            }
            if ( !Config.ALT_NONPVP )
            { // Non-PvP設定
                if ( getMap().isCombatZone( getLocation() ) )
                {
                    return false;
                }

                // 全戦争リストを取得
                foreach ( L1War war in L1World.getInstance().getWarList() )
                {
                    if ( pc.getClanid() != 0 && targetpc.getClanid() != 0 )
                    { // 共にクラン所属中
                        bool same_war = war.CheckClanInSameWar( pc.getClanname(), targetpc.getClanname() );
                        if ( same_war == true )
                        { // 同じ戦争に参加中
                            return false;
                        }
                    }
                }
                // Non-PvP設定でも戦争中は布告なしで攻撃可能
                if ( target is L1PcInstance )
                {
                    L1PcInstance targetPc = (L1PcInstance)target;
                    if ( isInWarAreaAndWarTime( pc, targetPc ) )
                    {
                        return false;
                    }
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        private bool isInWarAreaAndWarTime( L1PcInstance pc, L1PcInstance target )
        {
            // pcとtargetが戦争中に戦争エリアに居るか
            int castleId = L1CastleLocation.getCastleIdByArea( pc );
            int targetCastleId = L1CastleLocation.getCastleIdByArea( target );
            if ( castleId != 0 && targetCastleId != 0 && castleId == targetCastleId )
            {
                if ( WarTimeController.getInstance().isNowWar( castleId ) )
                {
                    return true;
                }
            }
            return false;
        }

        public void setPetTarget( L1Character target )
        {
            foreach ( Object pet in getPetList().Values )
            {
                if ( pet is L1PetInstance )
                {
                    L1PetInstance pets = (L1PetInstance)pet;
                    pets.setMasterTarget( target );
                }
                else if ( pet is L1SummonInstance )
                {
                    L1SummonInstance summon = (L1SummonInstance)pet;
                    summon.setMasterTarget( target );
                }
            }
        }

        public void delInvis()
        {
            // 魔法接続時間内はこちらを利用
            if ( hasSkillEffect( L1SkillId.INVISIBILITY ) )
            { // インビジビリティ
                killSkillEffectTimer( L1SkillId.INVISIBILITY );
                sendPackets( new S_Invis( getId(), 0 ) );
                broadcastPacket( new S_OtherCharPacks( this ) );
            }
            if ( hasSkillEffect( L1SkillId.BLIND_HIDING ) )
            { // ブラインド ハイディング
                killSkillEffectTimer( L1SkillId.BLIND_HIDING );
                sendPackets( new S_Invis( getId(), 0 ) );
                broadcastPacket( new S_OtherCharPacks( this ) );
            }
        }

        public void delBlindHiding()
        {
            // 魔法接続時間終了はこちら
            killSkillEffectTimer( L1SkillId.BLIND_HIDING );
            sendPackets( new S_Invis( getId(), 0 ) );
            broadcastPacket( new S_OtherCharPacks( this ) );
        }

        // 魔法のダメージの場合はここを使用 (ここで魔法ダメージ軽減処理) attr:0.無属性魔法,1.地魔法,2.火魔法,3.水魔法,4.風魔法
        public void receiveDamage( L1Character attacker, int damage, int attr )
        {
            int player_mr = getMr();
            int rnd = _random.Next( 100 ) + 1;
            if ( player_mr >= rnd )
            {
                damage /= 2;
            }
            receiveDamage( attacker, damage, false );
        }

        public void receiveManaDamage( L1Character attacker, int mpDamage )
        { // 攻撃でＭＰを減らすときはここを使用
            if ( mpDamage > 0 && !isDead() )
            {
                delInvis();
                if ( attacker is L1PcInstance )
                {
                    L1PinkName.onAction( this, attacker );
                }
                if ( attacker is L1PcInstance
                        && ( (L1PcInstance)attacker ).isPinkName() )
                {
                    // ガードが画面内にいれば、攻撃者をガードのターゲットに設定する
                    foreach ( L1Object l1object in L1World.getInstance().getVisibleObjects( attacker ) )
                    {
                        if ( l1object is L1GuardInstance )
                        {
                            L1GuardInstance guard = (L1GuardInstance)l1object;
                            guard.setTarget( ( (L1PcInstance)attacker ) );
                        }
                    }
                }

                int newMp = getCurrentMp() - mpDamage;
                if ( newMp > getMaxMp() )
                {
                    newMp = getMaxMp();
                }

                if ( newMp <= 0 )
                {
                    newMp = 0;
                }
                setCurrentMp( newMp );
            }
        }

        public long _oldTime = 0; // 連続魔法ダメージの軽減に使用する

        public void receiveDamage( L1Character attacker, double damage, bool isMagicDamage )
        {
            // 攻撃でＨＰを減らすときはここを使用
            if ( getCurrentHp() > 0 && !isDead() )
            {
                if ( attacker != this )
                {
                    if ( !( attacker is L1EffectInstance )
                            && !knownsObject( attacker )
                            && attacker.getMapId() == this.getMapId() )
                    {
                        attacker.onPerceive( this );
                    }
                }

                if ( isMagicDamage == true )
                { // 連続魔法ダメージによる軽減
                    long nowTime = DateTime.Today.Ticks / 10000;
                    long interval = nowTime - _oldTime;

                    if ( damage < 0 )
                    {
                        //damage = damage; // TODO どういう意味？！
                    }
                    else
                    {
                        if ( 2000 > interval && interval >= 1900 )
                        {
                            damage = ( damage * ( 100 - ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 1900 > interval && interval >= 1800 )
                        {
                            damage = ( damage * ( 100 - 2 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 1800 > interval && interval >= 1700 )
                        {
                            damage = ( damage * ( 100 - 3 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 1700 > interval && interval >= 1600 )
                        {
                            damage = ( damage * ( 100 - 4 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 1600 > interval && interval >= 1500 )
                        {
                            damage = ( damage * ( 100 - 5 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 1500 > interval && interval >= 1400 )
                        {
                            damage = ( damage * ( 100 - 6 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 1400 > interval && interval >= 1300 )
                        {
                            damage = ( damage * ( 100 - 7 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 1300 > interval && interval >= 1200 )
                        {
                            damage = ( damage * ( 100 - 8 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 1200 > interval && interval >= 1100 )
                        {
                            damage = ( damage * ( 100 - 9 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 1100 > interval && interval >= 1000 )
                        {
                            damage = ( damage * ( 100 - 10 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 1000 > interval && interval >= 900 )
                        {
                            damage = ( damage * ( 100 - 11 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 900 > interval && interval >= 800 )
                        {
                            damage = ( damage * ( 100 - 12 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 800 > interval && interval >= 700 )
                        {
                            damage = ( damage * ( 100 - 13 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 700 > interval && interval >= 600 )
                        {
                            damage = ( damage * ( 100 - 14 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 600 > interval && interval >= 500 )
                        {
                            damage = ( damage * ( 100 - 15 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 500 > interval && interval >= 400 )
                        {
                            damage = ( damage * ( 100 - 16 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 400 > interval && interval >= 300 )
                        {
                            damage = ( damage * ( 100 - 17 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 300 > interval && interval >= 200 )
                        {
                            damage = ( damage * ( 100 - 18 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 200 > interval && interval >= 100 )
                        {
                            damage = ( damage * ( 100 - 19 * ( 10 / 3 ) ) ) / 100;
                        }
                        else if ( 100 > interval && interval >= 0 )
                        {
                            damage = ( damage * ( 100 - 20 * ( 10 / 3 ) ) ) / 100;
                        }
                        else
                        {
                            //damage = damage;//TODO どういう意味？！
                        }

                        if ( damage < 1 )
                        {
                            damage = 0;
                        }

                        _oldTime = nowTime; // 次回のために時間を保存
                    }
                }
                if ( damage > 0 )
                {
                    delInvis();
                    if ( attacker is L1PcInstance )
                    {
                        L1PinkName.onAction( this, attacker );
                    }
                    if ( attacker is L1PcInstance && ( (L1PcInstance)attacker ).isPinkName() )
                    {
                        // ガードが画面内にいれば、攻撃者をガードのターゲットに設定する
                        foreach ( L1Object l1object in L1World.getInstance().getVisibleObjects( attacker ) )
                        {
                            if ( l1object is L1GuardInstance )
                            {
                                L1GuardInstance guard = (L1GuardInstance)l1object;
                                guard.setTarget( ( (L1PcInstance)attacker ) );
                            }
                        }
                    }
                    removeSkillEffect( L1SkillId.FOG_OF_SLEEPING );
                }

                if ( hasSkillEffect( L1SkillId.MORTAL_BODY )
                        && getId() != attacker.getId() )
                {
                    int rnd = _random.Next( 100 ) + 1;
                    if ( damage > 0 && rnd <= 10 )
                    {
                        if ( attacker is L1PcInstance )
                        {
                            L1PcInstance attackPc = (L1PcInstance)attacker;
                            attackPc.sendPackets( new S_DoActionGFX( attackPc.getId(), ActionCodes.ACTION_Damage ) );
                            attackPc.broadcastPacket( new S_DoActionGFX( attackPc.getId(), ActionCodes.ACTION_Damage ) );
                            attackPc.receiveDamage( this, 30, false );
                        }
                        else if ( attacker is L1NpcInstance )
                        {
                            L1NpcInstance attackNpc = (L1NpcInstance)attacker;
                            attackNpc.broadcastPacket( new S_DoActionGFX( attackNpc.getId(), ActionCodes.ACTION_Damage ) );
                            attackNpc.receiveDamage( this, 30 );
                        }
                    }
                }
                if ( attacker.hasSkillEffect( L1SkillId.JOY_OF_PAIN )
                        && getId() != attacker.getId() )
                {
                    int nowDamage = getMaxHp() - getCurrentHp();
                    if ( nowDamage > 0 )
                    {
                        if ( attacker is L1PcInstance )
                        {
                            L1PcInstance attackPc = (L1PcInstance)attacker;
                            attackPc.sendPackets( new S_DoActionGFX( attackPc
                                    .getId(), ActionCodes.ACTION_Damage ) );
                            attackPc.broadcastPacket( new S_DoActionGFX( attackPc
                                    .getId(), ActionCodes.ACTION_Damage ) );
                            attackPc.receiveDamage( this, (int)( nowDamage / 5 ), false );
                        }
                        else if ( attacker is L1NpcInstance )
                        {
                            L1NpcInstance attackNpc = (L1NpcInstance)attacker;
                            attackNpc.broadcastPacket( new S_DoActionGFX( attackNpc
                                    .getId(), ActionCodes.ACTION_Damage ) );
                            attackNpc.receiveDamage( this, (int)( nowDamage / 5 ) );
                        }
                    }
                }
                if ( getInventory().checkEquipped( 145 ) // バーサーカーアックス
                        || getInventory().checkEquipped( 149 ) )
                {
                    // ミノタウルスアックス
                    damage *= 1.5; // 被ダメ1.5倍
                }
                if ( hasSkillEffect( L1SkillId.ILLUSION_AVATAR ) )
                {
                    damage *= 1.5; // 被ダメ1.5倍
                }
                int newHp = getCurrentHp() - (int)( damage );
                if ( newHp > getMaxHp() )
                {
                    newHp = getMaxHp();
                }
                if ( newHp <= 0 )
                {
                    if ( isGm() )
                    {
                        setCurrentHp( getMaxHp() );
                    }
                    else
                    {
                        death( attacker );
                    }
                }
                if ( newHp > 0 )
                {
                    setCurrentHp( newHp );
                }
            }
            else if ( !isDead() )
            {
                // 念のため
                _log.info( "警告：プレイヤーのＨＰ減少処理が正しく行われていない箇所があります。※もしくは最初からＨＰ０" );
                death( attacker );
            }
        }

        public void death( L1Character lastAttacker )
        {
            lock ( this )
            {
                if ( isDead() )
                {
                    return;
                }
                setDead( true );
                setStatus( ActionCodes.ACTION_Die );
            }
            // TODO 優先度9 スレッドプール
            //GeneralThreadPool.getInstance().execute(new Death(lastAttacker));
            Death death = new Death( lastAttacker );
            ThreadPool.QueueUserWorkItem( new WaitCallback( death.run ) );
        }

        private class Death : L1PcInstance
        {
            L1Character _lastAttacker;

            public Death( L1Character cha )
            {
                _lastAttacker = cha;
            }

            public void run( object state )
            {
                L1Character lastAttacker = _lastAttacker;
                _lastAttacker = null;
                setCurrentHp( 0 );
                setGresValid( false ); // EXPロストするまでG-RES無効

                while ( isTeleport() )
                { // テレポート中なら終わるまで待つ
                    Thread.Sleep( 300 );
                }

                stopHpRegeneration();
                stopMpRegeneration();

                int targetobjid = getId();
                getMap().setPassable( getLocation(), true );

                // エンチャントを解除する
                // 変身状態も解除されるため、キャンセレーションをかけてから変身状態に戻す
                int tempchargfx = 0;
                if ( hasSkillEffect( L1SkillId.SHAPE_CHANGE ) )
                {
                    tempchargfx = getTempCharGfx();
                    setTempCharGfxAtDead( tempchargfx );
                }
                else
                {
                    setTempCharGfxAtDead( getClassId() );
                }

                // キャンセレーションをエフェクトなしでかける
                L1SkillUse l1skilluse = new L1SkillUse();
                l1skilluse.handleCommands( this,
                        L1SkillId.CANCELLATION, getId(), getX(), getY(), null, 0,
                        L1SkillUse.TYPE_LOGIN );

                // シャドウ系変身中に死亡するとクライアントが落ちるため暫定対応
                if ( tempchargfx == 5727 || tempchargfx == 5730
                        || tempchargfx == 5733 || tempchargfx == 5736 )
                {
                    tempchargfx = 0;
                }
                if ( tempchargfx != 0 )
                {
                    sendPackets( new S_ChangeShape( getId(), tempchargfx ) );
                    broadcastPacket( new S_ChangeShape( getId(), tempchargfx ) );
                }
                else
                {
                    // シャドウ系変身中に攻撃しながら死亡するとクライアントが落ちるためディレイを入れる
                    Thread.Sleep( 1000 );
                }

                sendPackets( new S_DoActionGFX( targetobjid, ActionCodes.ACTION_Die ) );
                broadcastPacket( new S_DoActionGFX( targetobjid,
                        ActionCodes.ACTION_Die ) );

                if ( lastAttacker != this )
                {
                    // セーフティーゾーン、コンバットゾーンで最後に殺したキャラが
                    // プレイヤーorペットだったら、ペナルティなし
                    if ( getZoneType() != 0 )
                    {
                        L1PcInstance player = null;
                        if ( lastAttacker is L1PcInstance )
                        {
                            player = (L1PcInstance)lastAttacker;
                        }
                        else if ( lastAttacker is L1PetInstance )
                        {
                            player = (L1PcInstance)( (L1PetInstance)lastAttacker )
                                    .getMaster();
                        }
                        else if ( lastAttacker is L1SummonInstance )
                        {
                            player = (L1PcInstance)( (L1SummonInstance)lastAttacker )
                                    .getMaster();
                        }
                        if ( player != null )
                        {
                            // 戦争中に戦争エリアに居る場合は例外
                            if ( !isInWarAreaAndWarTime( this, player ) )
                            {
                                return;
                            }
                        }
                    }

                    bool sim_ret = simWarResult( lastAttacker ); // 模擬戦
                    if ( sim_ret == true )
                    { // 模擬戦中ならペナルティなし
                        return;
                    }
                }

                if ( !getMap().isEnabledDeathPenalty() )
                {
                    return;
                }

                // 決闘中ならペナルティなし
                L1PcInstance fightPc = null;
                if ( lastAttacker is L1PcInstance )
                {
                    fightPc = (L1PcInstance)lastAttacker;
                }
                if ( fightPc != null )
                {
                    if ( getFightId() == fightPc.getId()
                            && fightPc.getFightId() == getId() )
                    { // 決闘中
                        setFightId( 0 );
                        sendPackets( new S_PacketBox( S_PacketBox.MSG_DUEL, 0, 0 ) );
                        fightPc.setFightId( 0 );
                        fightPc.sendPackets( new S_PacketBox( S_PacketBox.MSG_DUEL,
                                0, 0 ) );
                        return;
                    }
                }

                deathPenalty(); // EXPロスト

                setGresValid( true ); // EXPロストしたらG-RES有効

                if ( getExpRes() == 0 )
                {
                    setExpRes( 1 );
                }

                // ガードに殺された場合のみ、PKカウントを減らしガードに攻撃されなくなる
                if ( lastAttacker is L1GuardInstance )
                {
                    if ( get_PKcount() > 0 )
                    {
                        set_PKcount( get_PKcount() - 1 );
                    }
                    setLastPk( null );
                }
                if ( lastAttacker is L1GuardianInstance )
                {
                    if ( getPkCountForElf() > 0 )
                    {
                        setPkCountForElf( getPkCountForElf() - 1 );
                    }
                    setLastPkForElf( null );
                }

                // 一定の確率でアイテムをDROP
                // アライメント32000以上で0%、以降-1000毎に0.4%
                // アライメントが0未満の場合は-1000毎に0.8%
                // アライメント-32000以下で最高51.2%のDROP率
                int lostRate = (int)( ( ( getLawful() + 32768D ) / 1000D - 65D ) * 4D );
                if ( lostRate < 0 )
                {
                    lostRate *= -1;
                    if ( getLawful() < 0 )
                    {
                        lostRate *= 2;
                    }
                    int rnd = _random.Next( 1000 ) + 1;
                    if ( rnd <= lostRate )
                    {
                        int count = 1;
                        if ( getLawful() <= -30000 )
                        {
                            count = _random.Next( 4 ) + 1;
                        }
                        else if ( getLawful() <= -20000 )
                        {
                            count = _random.Next( 3 ) + 1;
                        }
                        else if ( getLawful() <= -10000 )
                        {
                            count = _random.Next( 2 ) + 1;
                        }
                        else if ( getLawful() < 0 )
                        {
                            count = _random.Next( 1 ) + 1;
                        }
                        caoPenaltyResult( count );
                    }
                }

                bool castle_ret = castleWarResult(); // 攻城戦
                if ( castle_ret == true )
                { // 攻城戦中で旗内なら赤ネームペナルティなし
                    return;
                }

                // 最後に殺したキャラがプレイヤーだったら、赤ネームにする
                L1PcInstance player2 = null;
                if ( lastAttacker is L1PcInstance )
                {
                    player2 = (L1PcInstance)lastAttacker;
                }
                if ( player2 != null )
                {
                    if ( getLawful() >= 0 && isPinkName() == false )
                    {
                        bool isChangePkCount = false;
                        //bool isChangePkCountForElf = false;
                        // アライメントが30000未満の場合はPKカウント増加
                        if ( player2.getLawful() < 30000 )
                        {
                            player2.set_PKcount( player2.get_PKcount() + 1 );
                            isChangePkCount = true;
                            if ( player2.isElf() && isElf() )
                            {
                                player2.setPkCountForElf( player2
                                        .getPkCountForElf() + 1 );
                                //isChangePkCountForElf = true;
                            }
                        }
                        player2.setLastPk();
                        if ( player2.isElf() && isElf() )
                        {
                            player2.setLastPkForElf();
                        }

                        // アライメント処理
                        // 公式の発表および各LVでのPKからつじつまの合うように変更
                        // （PK側のLVに依存し、高LVほどリスクも高い）
                        // 48あたりで-8kほど DKの時点で10k強
                        // 60で約20k強 65で30k弱
                        int lawful;

                        if ( player2.getLevel() < 50 )
                        {
                            lawful = -1
                                    * (int)( ( Math.Pow( player2.getLevel(), 2 ) * 4 ) );
                        }
                        else
                        {
                            lawful = -1
                                    * (int)( ( Math.Pow( player2.getLevel(), 3 ) * 0.08 ) );
                        }
                        // もし(元々のアライメント-1000)が計算後より低い場合
                        // 元々のアライメント-1000をアライメント値とする
                        // （連続でPKしたときにほとんど値が変わらなかった記憶より）
                        // これは上の式よりも自信度が低いうろ覚えですので
                        // 明らかにこうならない！という場合は修正お願いします
                        if ( ( player2.getLawful() - 1000 ) < lawful )
                        {
                            lawful = player2.getLawful() - 1000;
                        }

                        if ( lawful <= -32768 )
                        {
                            lawful = -32768;
                        }
                        player2.setLawful( lawful );

                        S_Lawful s_lawful = new S_Lawful( player2.getId(), player2
                                .getLawful() );
                        player2.sendPackets( s_lawful );
                        player2.broadcastPacket( s_lawful );

                        if ( isChangePkCount && player2.get_PKcount() >= 5
                                && player2.get_PKcount() < 10 )
                        {
                            // あなたのPK回数が%0になりました。回数が%1になると地獄行きです。
                            player2.sendPackets( new S_BlueMessage( 551, player2.get_PKcount().ToString(), "10" ) );
                        }
                        else if ( isChangePkCount && player2.get_PKcount() >= 10 )
                        {
                            player2.beginHell( true );
                        }
                    }
                    else
                    {
                        setPinkName( false );
                    }
                }
                _pcDeleteTimer = new L1PcDeleteTimer( this );
                _pcDeleteTimer.begin();
            }
        }

        public void stopPcDeleteTimer()
        {
            if ( _pcDeleteTimer != null )
            {
                _pcDeleteTimer.cancel();
                _pcDeleteTimer = null;
            }
        }

        private void caoPenaltyResult( int count )
        {
            for ( int i = 0; i < count; i++ )
            {
                L1ItemInstance item = getInventory().CaoPenalty();

                if ( item != null )
                {
                    getInventory().tradeItem(
                            item,
                            item.isStackable() ? item.getCount() : 1,
                            L1World.getInstance().getInventory( getX(), getY(),
                                    getMapId() ) );
                    sendPackets( new S_ServerMessage( 638, item.getLogName() ) ); // %0を失いました。
                }
                else
                {
                }
            }
        }

        public bool castleWarResult()
        {
            if ( getClanid() != 0 && isCrown() )
            { // クラン所属中プリのチェック
                L1Clan clan = L1World.getInstance().getClan( getClanname() );
                // 全戦争リストを取得
                foreach ( L1War war in L1World.getInstance().getWarList() )
                {
                    int warType = war.GetWarType();
                    bool isInWar = war.CheckClanInWar( getClanname() );
                    bool isAttackClan = war.CheckAttackClan( getClanname() );
                    if ( getId() == clan.getLeaderId() && // 血盟主で攻撃側で攻城戦中
                            warType == 1 && isInWar && isAttackClan )
                    {
                        String enemyClanName = war.GetEnemyClanName( getClanname() );
                        if ( enemyClanName != null )
                        {
                            war.CeaseWar( getClanname(), enemyClanName ); // 終結
                        }
                        break;
                    }
                }
            }

            int castleId = 0;
            bool isNowWar = false;
            castleId = L1CastleLocation.getCastleIdByArea( this );
            if ( castleId != 0 )
            { // 旗内に居る
                isNowWar = WarTimeController.getInstance().isNowWar( castleId );
            }
            return isNowWar;
        }

        public bool simWarResult( L1Character lastAttacker )
        {
            if ( getClanid() == 0 )
            { // クラン所属していない
                return false;
            }
            if ( Config.SIM_WAR_PENALTY )
            { // 模擬戦ペナルティありの場合はfalse
                return false;
            }
            L1PcInstance attacker = null;
            String enemyClanName = null;
            bool sameWar = false;

            if ( lastAttacker is L1PcInstance )
            {
                attacker = (L1PcInstance)lastAttacker;
            }
            else if ( lastAttacker is L1PetInstance )
            {
                attacker = (L1PcInstance)( (L1PetInstance)lastAttacker )
                        .getMaster();
            }
            else if ( lastAttacker is L1SummonInstance )
            {
                attacker = (L1PcInstance)( (L1SummonInstance)lastAttacker )
                        .getMaster();
            }
            else
            {
                return false;
            }

            // 全戦争リストを取得
            foreach ( L1War war in L1World.getInstance().getWarList() )
            {
                L1Clan clan = L1World.getInstance().getClan( getClanname() );

                int warType = war.GetWarType();
                bool isInWar = war.CheckClanInWar( getClanname() );
                if ( attacker != null && attacker.getClanid() != 0 )
                { // lastAttackerがPC、サモン、ペットでクラン所属中
                    sameWar = war.CheckClanInSameWar( getClanname(), attacker
                            .getClanname() );
                }

                if ( getId() == clan.getLeaderId() && // 血盟主で模擬戦中
                        warType == 2 && isInWar == true )
                {
                    enemyClanName = war.GetEnemyClanName( getClanname() );
                    if ( enemyClanName != null )
                    {
                        war.CeaseWar( getClanname(), enemyClanName ); // 終結
                    }
                }

                if ( warType == 2 && sameWar )
                {// 模擬戦で同じ戦争に参加中の場合、ペナルティなし
                    return true;
                }
            }
            return false;
        }

        public void resExp()
        {
            int oldLevel = getLevel();
            int needExp = ExpTable.getNeedExpNextLevel( oldLevel );
            int exp = 0;
            if ( oldLevel < 45 )
            {
                exp = (int)( needExp * 0.05 );
            }
            else if ( oldLevel == 45 )
            {
                exp = (int)( needExp * 0.045 );
            }
            else if ( oldLevel == 46 )
            {
                exp = (int)( needExp * 0.04 );
            }
            else if ( oldLevel == 47 )
            {
                exp = (int)( needExp * 0.035 );
            }
            else if ( oldLevel == 48 )
            {
                exp = (int)( needExp * 0.03 );
            }
            else if ( oldLevel >= 49 )
            {
                exp = (int)( needExp * 0.025 );
            }

            if ( exp == 0 )
            {
                return;
            }
            addExp( exp );
        }

        public void deathPenalty()
        {
            int oldLevel = getLevel();
            int needExp = ExpTable.getNeedExpNextLevel( oldLevel );
            int exp = 0;
            if ( oldLevel >= 1 && oldLevel < 11 )
            {
                exp = 0;
            }
            else if ( oldLevel >= 11 && oldLevel < 45 )
            {
                exp = (int)( needExp * 0.1 );
            }
            else if ( oldLevel == 45 )
            {
                exp = (int)( needExp * 0.09 );
            }
            else if ( oldLevel == 46 )
            {
                exp = (int)( needExp * 0.08 );
            }
            else if ( oldLevel == 47 )
            {
                exp = (int)( needExp * 0.07 );
            }
            else if ( oldLevel == 48 )
            {
                exp = (int)( needExp * 0.06 );
            }
            else if ( oldLevel >= 49 )
            {
                exp = (int)( needExp * 0.05 );
            }

            if ( exp == 0 )
            {
                return;
            }
            addExp( -exp );
        }

        private int _originalEr = 0; // ● オリジナルDEX ER補正

        public int getOriginalEr()
        {

            return _originalEr;
        }

        public int getEr()
        {
            if ( hasSkillEffect( L1SkillId.STRIKER_GALE ) )
            {
                return 0;
            }

            int er = 0;
            if ( isKnight() )
            {
                er = getLevel() / 4; // ナイト
            }
            else if ( isCrown() || isElf() )
            {
                er = getLevel() / 8; // 君主・エルフ
            }
            else if ( isDarkelf() )
            {
                er = getLevel() / 6; // ダークエルフ
            }
            else if ( isWizard() )
            {
                er = getLevel() / 10; // ウィザード
            }
            else if ( isDragonKnight() )
            {
                er = getLevel() / 7; // ドラゴンナイト
            }
            else if ( isIllusionist() )
            {
                er = getLevel() / 9; // イリュージョニスト
            }

            er += ( getDex() - 8 ) / 2;

            er += getOriginalEr();

            if ( hasSkillEffect( L1SkillId.DRESS_EVASION ) )
            {
                er += 12;
            }
            if ( hasSkillEffect( L1SkillId.SOLID_CARRIAGE ) )
            {
                er += 15;
            }
            return er;
        }

        public L1BookMark getBookMark( String name )
        {
            for ( int i = 0; i < _bookmarks.Count; i++ )
            {
                L1BookMark element = _bookmarks[i];
                if ( string.Compare( element.getName(), name,true ) ==0)
                {
                    return element;
                }

            }
            return null;
        }

        public L1BookMark getBookMark( int id )
        {
            for ( int i = 0; i < _bookmarks.Count; i++ )
            {
                L1BookMark element = _bookmarks[i];
                if ( element.getId() == id )
                {
                    return element;
                }

            }
            return null;
        }

        public int getBookMarkSize()
        {
            return _bookmarks.Count;
        }

        public void addBookMark( L1BookMark book )
        {
            _bookmarks.Add( book );
        }

        public void removeBookMark( L1BookMark book )
        {
            _bookmarks.Remove( book );
        }

        public L1ItemInstance getWeapon()
        {
            return _weapon;
        }

        public void setWeapon( L1ItemInstance weapon )
        {
            _weapon = weapon;
        }

        public L1Quest getQuest()
        {
            return _quest;
        }

        public bool isCrown()
        {
            return ( getClassId() == CLASSID_PRINCE || getClassId() == CLASSID_PRINCESS );
        }

        public bool isKnight()
        {
            return ( getClassId() == CLASSID_KNIGHT_MALE || getClassId() == CLASSID_KNIGHT_FEMALE );
        }

        public bool isElf()
        {
            return ( getClassId() == CLASSID_ELF_MALE || getClassId() == CLASSID_ELF_FEMALE );
        }

        public bool isWizard()
        {
            return ( getClassId() == CLASSID_WIZARD_MALE || getClassId() == CLASSID_WIZARD_FEMALE );
        }

        public bool isDarkelf()
        {
            return ( getClassId() == CLASSID_DARK_ELF_MALE || getClassId() == CLASSID_DARK_ELF_FEMALE );
        }

        public bool isDragonKnight()
        {
            return ( getClassId() == CLASSID_DRAGON_KNIGHT_MALE || getClassId() == CLASSID_DRAGON_KNIGHT_FEMALE );
        }
        public bool isIllusionist()
        {
            return ( getClassId() == CLASSID_ILLUSIONIST_MALE || getClassId() == CLASSID_ILLUSIONIST_FEMALE );
        }

        private static Logger _log = Logger.getLogger( typeof( L1PcInstance ).FullName );
        private ClientThread _netConnection;
        private int _classId;
        private int _type;
        private int _exp;
        private L1Karma _karma = new L1Karma();
        private bool _gm;
        private bool _monitor;
        private bool _gmInvis;
        private short _accessLevel;
        private int _currentWeapon;
        private L1PcInventory _inventory;
        private L1DwarfInventory _dwarf;
        private L1DwarfForElfInventory _dwarfForElf;
        private L1Inventory _tradewindow;
        private L1ItemInstance _weapon;
        private L1Party _party;
        private L1ChatParty _chatParty;
        private int _partyID;
        private int _tradeID;
        private bool _tradeOk;
        private int _tempID;
        private bool _isTeleport = false;
        private bool _isDrink = false;
        private bool _isGres = false;
        private bool _isPinkName = false;
        private List<L1BookMark> _bookmarks;
        private L1Quest _quest;
        private MpRegeneration _mpRegen;
        private MpRegenerationByDoll _mpRegenByDoll;
        private MpReductionByAwake _mpReductionByAwake;
        private HpRegeneration _hpRegen;
        private Timer _regenTimer;
        private bool _mpRegenActive;
        private bool _mpRegenActiveByDoll;
        private bool _mpReductionActiveByAwake;
        private bool _hpRegenActive;
        private L1EquipmentSlot _equipSlot;
        private L1PcDeleteTimer _pcDeleteTimer;

        private String _accountName; // ● アカウントネーム

        public String getAccountName()
        {
            return _accountName;
        }

        public void setAccountName( String s )
        {
            _accountName = s;
        }

        private short _baseMaxHp = 0; // ● ＭＡＸＨＰベース（1～32767）

        public short getBaseMaxHp()
        {
            return _baseMaxHp;
        }

        public void addBaseMaxHp( short i )
        {
            i += _baseMaxHp;
            if ( i >= 32767 )
            {
                i = 32767;
            }
            else if ( i < 1 )
            {
                i = 1;
            }
            addMaxHp( i - _baseMaxHp );
            _baseMaxHp = i;
        }

        private short _baseMaxMp = 0; // ● ＭＡＸＭＰベース（0～32767）

        public short getBaseMaxMp()
        {
            return _baseMaxMp;
        }

        public void addBaseMaxMp( short i )
        {
            i += _baseMaxMp;
            if ( i >= 32767 )
            {
                i = 32767;
            }
            else if ( i < 0 )
            {
                i = 0;
            }
            addMaxMp( i - _baseMaxMp );
            _baseMaxMp = i;
        }

        private int _baseAc = 0; // ● ＡＣベース（-128～127）

        public int getBaseAc()
        {
            return _baseAc;
        }

        private int _originalAc = 0; // ● オリジナルDEX ＡＣ補正

        public int getOriginalAc()
        {

            return _originalAc;
        }


        private byte _baseStr = 0; // ● ＳＴＲベース（1～127）

        public byte getBaseStr()
        {
            return _baseStr;
        }

        public void addBaseStr( byte i )
        {
            i += _baseStr;
            if ( i >= 127 )
            {
                i = 127;
            }
            else if ( i < 1 )
            {
                i = 1;
            }
            addStr( (byte)( i - _baseStr ) );
            _baseStr = i;
        }

        private byte _baseCon = 0; // ● ＣＯＮベース（1～127）

        public byte getBaseCon()
        {
            return _baseCon;
        }

        public void addBaseCon( byte i )
        {
            i += _baseCon;
            if ( i >= 127 )
            {
                i = 127;
            }
            else if ( i < 1 )
            {
                i = 1;
            }
            addCon( (byte)( i - _baseCon ) );
            _baseCon = i;
        }

        private byte _baseDex = 0; // ● ＤＥＸベース（1～127）

        public byte getBaseDex()
        {
            return _baseDex;
        }

        public void addBaseDex( byte i )
        {
            i += _baseDex;
            if ( i >= 127 )
            {
                i = 127;
            }
            else if ( i < 1 )
            {
                i = 1;
            }
            addDex( (byte)( i - _baseDex ) );
            _baseDex = i;
        }

        private byte _baseCha = 0; // ● ＣＨＡベース（1～127）

        public byte getBaseCha()
        {
            return _baseCha;
        }

        public void addBaseCha( byte i )
        {
            i += _baseCha;
            if ( i >= 127 )
            {
                i = 127;
            }
            else if ( i < 1 )
            {
                i = 1;
            }
            addCha( (byte)( i - _baseCha ) );
            _baseCha = i;
        }

        private byte _baseInt = 0; // ● ＩＮＴベース（1～127）

        public byte getBaseInt()
        {
            return _baseInt;
        }

        public void addBaseInt( byte i )
        {
            i += _baseInt;
            if ( i >= 127 )
            {
                i = 127;
            }
            else if ( i < 1 )
            {
                i = 1;
            }
            addInt( (byte)( i - _baseInt ) );
            _baseInt = i;
        }

        private byte _baseWis = 0; // ● ＷＩＳベース（1～127）

        public byte getBaseWis()
        {
            return _baseWis;
        }

        public void addBaseWis( byte i )
        {
            i += _baseWis;
            if ( i >= 127 )
            {
                i = 127;
            }
            else if ( i < 1 )
            {
                i = 1;
            }
            addWis( (byte)( i - _baseWis ) );
            _baseWis = i;
        }

        private int _originalStr = 0; // ● オリジナル STR

        public int getOriginalStr()
        {
            return _originalStr;
        }

        public void setOriginalStr( int i )
        {
            _originalStr = i;
        }

        private int _originalCon = 0; // ● オリジナル CON

        public int getOriginalCon()
        {
            return _originalCon;
        }

        public void setOriginalCon( int i )
        {
            _originalCon = i;
        }

        private int _originalDex = 0; // ● オリジナル DEX

        public int getOriginalDex()
        {
            return _originalDex;
        }

        public void setOriginalDex( int i )
        {
            _originalDex = i;
        }

        private int _originalCha = 0; // ● オリジナル CHA

        public int getOriginalCha()
        {
            return _originalCha;
        }

        public void setOriginalCha( int i )
        {
            _originalCha = i;
        }

        private int _originalInt = 0; // ● オリジナル INT

        public int getOriginalInt()
        {
            return _originalInt;
        }

        public void setOriginalInt( int i )
        {
            _originalInt = i;
        }

        private int _originalWis = 0; // ● オリジナル WIS

        public int getOriginalWis()
        {
            return _originalWis;
        }

        public void setOriginalWis( int i )
        {
            _originalWis = i;
        }

        private int _originalDmgup = 0; // ● オリジナルSTR ダメージ補正

        public int getOriginalDmgup()
        {
            return _originalDmgup;
        }

        private int _originalBowDmgup = 0; // ● オリジナルDEX 弓ダメージ補正

        public int getOriginalBowDmgup()
        {

            return _originalBowDmgup;
        }

        private int _originalHitup = 0; // ● オリジナルSTR 命中補正

        public int getOriginalHitup()
        {
            return _originalHitup;
        }

        private int _originalBowHitup = 0; // ● オリジナルDEX 命中補正

        public int getOriginalBowHitup()
        {
            return _originalHitup;
        }

        private int _originalMr = 0; // ● オリジナルWIS 魔法防御

        public int getOriginalMr()
        {
            return _originalMr;
        }

        private int _originalMagicHit = 0; // ● オリジナルINT 魔法命中

        public int getOriginalMagicHit()
        {
            return _originalMagicHit;
        }

        private int _originalMagicCritical = 0; // ● オリジナルINT 魔法クリティカル

        public int getOriginalMagicCritical()
        {
            return _originalMagicCritical;
        }

        private int _originalMagicConsumeReduction = 0; // ● オリジナルINT 消費MP軽減

        public int getOriginalMagicConsumeReduction()
        {
            return _originalMagicConsumeReduction;
        }

        private int _originalMagicDamage = 0; // ● オリジナルINT 魔法ダメージ

        public int getOriginalMagicDamage()
        {
            return _originalMagicDamage;
        }

        private int _originalHpup = 0; // ● オリジナルCON HP上昇値補正

        public int getOriginalHpup()
        {
            return _originalHpup;
        }

        private int _originalMpup = 0; // ● オリジナルWIS MP上昇値補正

        public int getOriginalMpup()
        {
            return _originalMpup;
        }

        private int _baseDmgup = 0; // ● ダメージ補正ベース（-128～127）

        public int getBaseDmgup()
        {
            return _baseDmgup;
        }

        private int _baseBowDmgup = 0; // ● 弓ダメージ補正ベース（-128～127）

        public int getBaseBowDmgup()
        {
            return _baseBowDmgup;
        }

        private int _baseHitup = 0; // ● 命中補正ベース（-128～127）

        public int getBaseHitup()
        {
            return _baseHitup;
        }

        private int _baseBowHitup = 0; // ● 弓命中補正ベース（-128～127）

        public int getBaseBowHitup()
        {
            return _baseBowHitup;
        }

        private int _baseMr = 0; // ● 魔法防御ベース（0～）

        public int getBaseMr()
        {
            return _baseMr;
        }

        private int _advenHp; // ● // アドバンスド スピリッツで増加しているＨＰ

        public int getAdvenHp()
        {
            return _advenHp;
        }

        public void setAdvenHp( int i )
        {
            _advenHp = i;
        }

        private int _advenMp; // ● // アドバンスド スピリッツで増加しているＭＰ

        public int getAdvenMp()
        {
            return _advenMp;
        }

        public void setAdvenMp( int i )
        {
            _advenMp = i;
        }

        private int _highLevel; // ● 過去最高レベル

        public int getHighLevel()
        {
            return _highLevel;
        }

        public void setHighLevel( int i )
        {
            _highLevel = i;
        }

        private int _bonusStats; // ● 割り振ったボーナスステータス

        public int getBonusStats()
        {
            return _bonusStats;
        }

        public void setBonusStats( int i )
        {
            _bonusStats = i;
        }

        private int _elixirStats; // ● エリクサーで上がったステータス

        public int getElixirStats()
        {
            return _elixirStats;
        }

        public void setElixirStats( int i )
        {
            _elixirStats = i;
        }

        private int _elfAttr; // ● エルフの属性

        public int getElfAttr()
        {
            return _elfAttr;
        }

        public void setElfAttr( int i )
        {
            _elfAttr = i;
        }

        private int _expRes; // ● EXP復旧

        public int getExpRes()
        {
            return _expRes;
        }

        public void setExpRes( int i )
        {
            _expRes = i;
        }

        private int _partnerId; // ● 結婚相手

        public int getPartnerId()
        {
            return _partnerId;
        }

        public void setPartnerId( int i )
        {
            _partnerId = i;
        }

        private int _onlineStatus; // ● オンライン状態

        public int getOnlineStatus()
        {
            return _onlineStatus;
        }

        /// <summary>
        /// オンライン状態に設定する。
        /// </summary>
        /// <param name="i"></param>
        public void setOnlineStatus( int i )
        {
            _onlineStatus = i;
        }

        private int _homeTownId; // ● ホームタウン

        public int getHomeTownId()
        {
            return _homeTownId;
        }

        public void setHomeTownId( int i )
        {
            _homeTownId = i;
        }

        private int _contribution; // ● 貢献度

        public int getContribution()
        {
            return _contribution;
        }

        public void setContribution( int i )
        {
            _contribution = i;
        }

        // 地獄に滞在する時間（秒）
        private int _hellTime;

        public int getHellTime()
        {
            return _hellTime;
        }

        public void setHellTime( int i )
        {
            _hellTime = i;
        }

        private bool _banned; // ● 凍結

        public bool isBanned()
        {
            return _banned;
        }

        public void setBanned( bool flag )
        {
            _banned = flag;
        }

        private int _food; // ● 満腹度

        public int get_food()
        {
            return _food;
        }

        public void set_food( int i )
        {
            _food = i;
        }

        public L1EquipmentSlot getEquipSlot()
        {
            return _equipSlot;
        }

        public static L1PcInstance load( String charName )
        {
            L1PcInstance result = null;
            result = CharacterTable.getInstance().loadCharacter( charName );

            return result;
        }

        /// <summary>
        /// このプレイヤーの状態をストレージへ書き込む。
        /// </summary>
        public void save()
        {
            if ( isGhost() )
            {
                return;
            }
            if ( isInCharReset() )
            {
                return;
            }

            CharacterTable.getInstance().storeCharacter( this );
        }

        /// <summary>
        /// このプレイヤーのインベントリアイテムの状態をストレージへ書き込む。
        /// </summary>
        public void saveInventory()
        {
            foreach ( L1ItemInstance item in getInventory().getItems() )
            {
                getInventory().saveItem( item, item.getRecordingColumns() );
            }
        }

        public const int REGENSTATE_NONE = 4;
        public const int REGENSTATE_MOVE = 2;
        public const int REGENSTATE_ATTACK = 1;

        public void setRegenState( int state )
        {
            _mpRegen.setState( state );
            _hpRegen.setState( state );
        }

        public double getMaxWeight()
        {
            int str = getStr();
            int con = getCon();
            double maxWeight = 150 * ( Math.Floor( 0.6 * str + 0.4 * con + 1 ) );

            double weightReductionByArmor = getWeightReduction(); // 防具による重量軽減
            weightReductionByArmor /= 100;

            double weightReductionByDoll = 0; // マジックドールによる重量軽減

            foreach ( L1DollInstance doll in getDollList().Values )
            {
                weightReductionByDoll += doll.getWeightReductionByDoll();
            }
            weightReductionByDoll /= 100;

            int weightReductionByMagic = 0;
            if ( hasSkillEffect( L1SkillId.DECREASE_WEIGHT ) )
            { // ディクリースウェイト
                weightReductionByMagic = 180;
            }

            double originalWeightReduction = 0; // オリジナルステータスによる重量軽減
            originalWeightReduction += 0.04 * ( getOriginalStrWeightReduction()
                    + getOriginalConWeightReduction() );

            double weightReduction = 1 + weightReductionByArmor
                    + weightReductionByDoll + originalWeightReduction;

            maxWeight *= weightReduction;

            maxWeight += weightReductionByMagic;

            maxWeight *= Config.RATE_WEIGHT_LIMIT; // ウェイトレートを掛ける

            return maxWeight;
        }

        public bool isFastMovable()
        {
            return ( hasSkillEffect( L1SkillId.HOLY_WALK )
                    || hasSkillEffect( L1SkillId.MOVING_ACCELERATION )
                    || hasSkillEffect( L1SkillId.WIND_WALK )
                    || hasSkillEffect( L1SkillId.STATUS_RIBRAVE ) );
        }

        public bool isFastAttackable()
        {
            return hasSkillEffect( L1SkillId.BLOODLUST );
        }

        public bool isBrave()
        {
            return hasSkillEffect( L1SkillId.STATUS_BRAVE );
        }

        public bool isElfBrave()
        {
            return hasSkillEffect( L1SkillId.STATUS_ELFBRAVE );
        }

        public bool isHaste()
        {
            return ( hasSkillEffect( L1SkillId.STATUS_HASTE )
                    || hasSkillEffect( L1SkillId.HASTE )
                    || hasSkillEffect( L1SkillId.GREATER_HASTE ) || getMoveSpeed() == 1 );
        }

        private int invisDelayCounter = 0;

        public bool isInvisDelay()
        {
            return ( invisDelayCounter > 0 );
        }

        private Object _invisTimerMonitor = new Object();

        public void addInvisDelayCounter( int counter )
        {
            lock ( _invisTimerMonitor )
            {
                invisDelayCounter += counter;
            }
        }

        private const long DELAY_INVIS = 3000L;

        public void beginInvisTimer()
        {
            addInvisDelayCounter( 1 );
            //GeneralThreadPool.getInstance().pcSchedule( new L1PcInvisDelay( getId() ), DELAY_INVIS );
            L1PcInvisDelay pid = new L1PcInvisDelay( getId() );
            Thread thread = new Thread( pid.run );
            thread.IsBackground = true;
            thread.Start( DELAY_INVIS );
        }

        public void addExp( int exp )
        {
            lock ( this )
            {
                _exp += exp;
                if ( _exp > ExpTable.MAX_EXP )
                {
                    _exp = ExpTable.MAX_EXP;
                }
            }
        }

        public void addContribution( int contribution )
        {
            lock ( this )
            {
                _contribution += contribution;
            }
        }

        public void beginExpMonitor()
        {
            //_expMonitorFuture = GeneralThreadPool.getInstance()
            //        .pcScheduleAtFixedRate( new L1PcExpMonitor( getId() ), 0L,
            //                INTERVAL_EXP_MONITOR );
            L1PcExpMonitor pem = new L1PcExpMonitor( getId() );
            _expMonitorFuture = new Timer( new TimerCallback( pem.run ), null, 0, INTERVAL_EXP_MONITOR );
        }

        private void levelUp( int gap )
        {
            resetLevel();

            // 復活のポーション
            if ( getLevel() == 99 && Config.ALT_REVIVAL_POTION )
            {
                L1Item l1item = ItemTable.getInstance().getTemplate( 43000 );
                if ( l1item != null )
                {
                    getInventory().storeItem( 43000, 1 );
                    sendPackets( new S_ServerMessage( 403, l1item.getName() ) );
                }
                else
                {
                    sendPackets( new S_SystemMessage( "復活のポーションの入手に失敗しました。" ) );
                }
            }

            for ( int i = 0; i < gap; i++ )
            {
                short randomHp = CalcStat.calcStatHp( getType(), getBaseMaxHp(),
                        getBaseCon(), getOriginalHpup() );
                short randomMp = CalcStat.calcStatMp( getType(), getBaseMaxMp(),
                        getBaseWis(), getOriginalMpup() );
                addBaseMaxHp( randomHp );
                addBaseMaxMp( randomMp );
            }
            resetBaseHitup();
            resetBaseDmgup();
            resetBaseAc();
            resetBaseMr();
            if ( getLevel() > getHighLevel() )
            {
                setHighLevel( getLevel() );
            }

            // DBにキャラクター情報を書き込む
            save();

            // ボーナスステータス
            if ( getLevel() >= 51 && getLevel() - 50 > getBonusStats() )
            {
                if ( ( getBaseStr() + getBaseDex() + getBaseCon() + getBaseInt()
                        + getBaseWis() + getBaseCha() ) < 210 )
                {
                    sendPackets( new S_bonusstats( getId(), 1 ) );
                }
            }
            sendPackets( new S_OwnCharStatus( this ) );
            if ( getLevel() >= 52 )
            { // 指定レベル
                if ( getMapId() == 777 )
                { // 見捨てられた者たちの地(影の神殿)
                    L1Teleport.teleport( this, 34043, 32184, (short)4, 5, true ); // 象牙の塔前
                }
                else if ( getMapId() == 778
                      || getMapId() == 779 )
                { // 見捨てられた者たちの地(欲望の洞窟)
                    L1Teleport.teleport( this, 32608, 33178, (short)4, 5, true ); // WB
                }
            }
        }

        private void levelDown( int gap )
        {
            resetLevel();

            for ( int i = 0; i > gap; i-- )
            {
                // レベルダウン時はランダム値をそのままマイナスする為に、base値に0を設定
                short randomHp = CalcStat.calcStatHp( getType(), 0, getBaseCon(), getOriginalHpup() );
                short randomMp = CalcStat.calcStatMp( getType(), 0, getBaseWis(), getOriginalMpup() );
                addBaseMaxHp( (short)-randomHp );
                addBaseMaxMp( (short)-randomMp );
            }
            resetBaseHitup();
            resetBaseDmgup();
            resetBaseAc();
            resetBaseMr();
            if ( Config.LEVEL_DOWN_RANGE != 0 )
            {
                if ( getHighLevel() - getLevel() >= Config.LEVEL_DOWN_RANGE )
                {
                    sendPackets( new S_ServerMessage( 64 ) ); // ワールドとの接続が切断されました。
                    sendPackets( new S_Disconnect() );
                    _log.info( String.Format( "レベルダウンの許容範囲を超えたため{0}を強制切断しました。",
                            getName() ) );
                }
            }

            // DBにキャラクター情報を書き込む
            save();
            sendPackets( new S_OwnCharStatus( this ) );
        }

        public void beginGameTimeCarrier()
        {
            new L1GameTimeCarrier( this ).start();
        }

        private bool _ghost = false; // ゴースト

        public bool isGhost()
        {
            return _ghost;
        }

        private void setGhost( bool flag )
        {
            _ghost = flag;
        }

        private bool _ghostCanTalk = true; // NPCに話しかけられるか

        public bool isGhostCanTalk()
        {
            return _ghostCanTalk;
        }

        private void setGhostCanTalk( bool flag )
        {
            _ghostCanTalk = flag;
        }

        private bool _isReserveGhost = false; // ゴースト解除準備

        public bool isReserveGhost()
        {
            return _isReserveGhost;
        }

        private void setReserveGhost( bool flag )
        {
            _isReserveGhost = flag;
        }

        public void beginGhost( int locx, int locy, short mapid, bool canTalk )
        {
            beginGhost( locx, locy, mapid, canTalk, 0 );
        }

        public void beginGhost( int locx, int locy, short mapid, bool canTalk,
                int sec )
        {
            if ( isGhost() )
            {
                return;
            }
            setGhost( true );
            _ghostSaveLocX = getX();
            _ghostSaveLocY = getY();
            _ghostSaveMapId = getMapId();
            _ghostSaveHeading = getHeading();
            setGhostCanTalk( canTalk );
            L1Teleport.teleport( this, locx, locy, mapid, 5, true );
            if ( sec > 0 )
            {
                // TODO 優先度9 スレッドプール
                //_ghostFuture = GeneralThreadPool.getInstance().pcSchedule(
                //        new L1PcGhostMonitor( getId() ), sec * 1000 );
                L1PcGhostMonitor pgm = new L1PcGhostMonitor( getId() );
                new Timer( new TimerCallback( pgm.run ), getId(), DELAY_INVIS, Timeout.Infinite );
            }
        }

        public void makeReadyEndGhost()
        {
            setReserveGhost( true );
            L1Teleport.teleport( this, _ghostSaveLocX, _ghostSaveLocY,
                    _ghostSaveMapId, _ghostSaveHeading, true );
        }

        public void endGhost()
        {
            setGhost( false );
            setGhostCanTalk( true );
            setReserveGhost( false );
        }

        private Timer _ghostFuture;

        private int _ghostSaveLocX = 0;
        private int _ghostSaveLocY = 0;
        private short _ghostSaveMapId = 0;
        private int _ghostSaveHeading = 0;

        private Timer _hellFuture;

        public void beginHell( bool isFirst )
        {
            // 地獄以外に居るときは地獄へ強制移動
            if ( getMapId() != 666 )
            {
                int locx = 32701;
                int locy = 32777;
                short mapid = 666;
                L1Teleport.teleport( this, locx, locy, mapid, 5, false );
            }

            if ( isFirst )
            {
                if ( get_PKcount() <= 10 )
                {
                    setHellTime( 300 );
                }
                else
                {
                    setHellTime( 300 * ( get_PKcount() - 10 ) + 300 );
                }
                // あなたのPK回数が%0になり、地獄に落とされました。あなたはここで%1分間反省しなければなりません。
                sendPackets( new S_BlueMessage( 552, Convert.ToString( get_PKcount() ),
                        Convert.ToString( getHellTime() / 60 ) ) );
            }
            else
            {
                // あなたは%0秒間ここにとどまらなければなりません。
                sendPackets( new S_BlueMessage( 637, Convert.ToString( getHellTime() ) ) );
            }
            if ( _hellFuture == null )
            {
                //_hellFuture = GeneralThreadPool.getInstance()
                //        .pcScheduleAtFixedRate( new L1PcHellMonitor( getId() ), 0L,
                //                1000L );
                L1PcHellMonitor phm = new L1PcHellMonitor( getId() );
                _hellFuture = new Timer( new TimerCallback( phm.run ), null, 0, 1000 );
            }
        }

        public void endHell()
        {
            if ( _hellFuture != null )
            {
                _hellFuture.Dispose();
                _hellFuture = null;
            }
            // 地獄から脱出したら火田村へ帰還させる。
            int[] loc = L1TownLocation
                    .getGetBackLoc( L1TownLocation.TOWNID_ORCISH_FOREST );
            L1Teleport.teleport( this, loc[0], loc[1], (short)loc[2], 5, true );
            save();
        }

        override
        public void setPoisonEffect( int effectId )
        {
            sendPackets( new S_Poison( getId(), effectId ) );

            if ( !isGmInvis() && !isGhost() && !isInvisble() )
            {
                broadcastPacket( new S_Poison( getId(), effectId ) );
            }
            if ( isGmInvis() || isGhost() )
            {
            }
            else if ( isInvisble() )
            {
                broadcastPacketForFindInvis( new S_Poison( getId(), effectId ),
                    true );
            }
            else
            {
                broadcastPacket( new S_Poison( getId(), effectId ) );
            }
        }

        override
        public void healHp( int pt )
        {
            base.healHp( pt );

            sendPackets( new S_HPUpdate( this ) );
        }

        public override int getKarma()
        {
            return _karma.get();
        }

        public override void setKarma( int i )
        {
            _karma.set( i );
        }

        Object lockKarma = new Object();
        public void addKarma( int i )
        {
            lock ( lockKarma )
            {
                _karma.add( i );
            }
        }

        public int getKarmaLevel()
        {
            return _karma.getLevel();
        }

        public int getKarmaPercent()
        {
            return _karma.getPercent();
        }

        private Nullable<DateTime> _lastPk;

        /// <summary>
        /// プレイヤーの最終PK時間を返す。
        /// </summary>
        /// <returns></returns>
        public Nullable<DateTime> getLastPk()
        {
            return _lastPk;
        }

        /// <summary>
        /// プレイヤーの最終PK時間を設定する。
        /// </summary>
        /// <param name="time">最終PK時間（Timestamp型） 解除する場合はnullを代入</param>
        public void setLastPk( Nullable<DateTime> time )
        {
            _lastPk = time;
        }


        /// <summary>
        /// プレイヤーの最終PK時間を現在の時刻に設定する。
        /// </summary>
        public void setLastPk()
        {
            _lastPk = DateTime.Now;
        }

        /// <summary>
        /// プレイヤーが手配中であるかを返す。
        /// </summary>
        /// <returns>手配中であれば、true</returns>
        public bool isWanted()
        {
            if ( _lastPk == null )
            {
                return false;
            }
            else if ( ( DateTime.Now - (DateTime)_lastPk ).TotalSeconds > 24 * 3600 )
            {
                setLastPk( null );
                return false;
            }
            return true;
        }

        private Nullable<DateTime> _lastPkForElf;

        public Nullable<DateTime> getLastPkForElf()
        {
            return _lastPkForElf;
        }

        public void setLastPkForElf( Nullable<DateTime> time )
        {
            _lastPkForElf = time;
        }

        public void setLastPkForElf()
        {
            _lastPkForElf = DateTime.Now;
        }

        public bool isWantedForElf()
        {
            if ( _lastPkForElf == null )
            {
                return false;
            }
            else if ( ( DateTime.Now - (DateTime)_lastPkForElf ).Days > 1 )
            {
                setLastPkForElf( null );
                return false;
            }
            return true;
        }

        private Nullable<DateTime> _deleteTime; // キャラクター削除までの時間

        public Nullable<DateTime> getDeleteTime()
        {
            return _deleteTime;
        }

        public void setDeleteTime( Nullable<DateTime> time )
        {
            _deleteTime = time;
        }

        override public int getMagicLevel()
        {
            return getClassFeature().getMagicLevel( getLevel() );
        }

        private int _weightReduction = 0;

        public int getWeightReduction()
        {
            return _weightReduction;
        }

        public void addWeightReduction( int i )
        {
            _weightReduction += i;
        }

        private int _originalStrWeightReduction = 0; // ● オリジナルSTR 重量軽減

        public int getOriginalStrWeightReduction()
        {

            return _originalStrWeightReduction;
        }

        private int _originalConWeightReduction = 0; // ● オリジナルCON 重量軽減

        public int getOriginalConWeightReduction()
        {

            return _originalConWeightReduction;
        }

        private int _hasteItemEquipped = 0;

        public int getHasteItemEquipped()
        {
            return _hasteItemEquipped;
        }

        public void addHasteItemEquipped( int i )
        {
            _hasteItemEquipped += i;
        }

        public void removeHasteSkillEffect()
        {
            if ( hasSkillEffect( L1SkillId.SLOW ) )
            {
                removeSkillEffect( L1SkillId.SLOW );
            }
            if ( hasSkillEffect( L1SkillId.MASS_SLOW ) )
            {
                removeSkillEffect( L1SkillId.MASS_SLOW );
            }
            if ( hasSkillEffect( L1SkillId.ENTANGLE ) )
            {
                removeSkillEffect( L1SkillId.ENTANGLE );
            }
            if ( hasSkillEffect( L1SkillId.HASTE ) )
            {
                removeSkillEffect( L1SkillId.HASTE );
            }
            if ( hasSkillEffect( L1SkillId.GREATER_HASTE ) )
            {
                removeSkillEffect( L1SkillId.GREATER_HASTE );
            }
            if ( hasSkillEffect( L1SkillId.STATUS_HASTE ) )
            {
                removeSkillEffect( L1SkillId.STATUS_HASTE );
            }
        }

        private int _damageReductionByArmor = 0; // 防具によるダメージ軽減

        public int getDamageReductionByArmor()
        {
            return _damageReductionByArmor;
        }

        public void addDamageReductionByArmor( int i )
        {
            _damageReductionByArmor += i;
        }

        private int _hitModifierByArmor = 0; // 防具による命中率補正

        public int getHitModifierByArmor()
        {
            return _hitModifierByArmor;
        }

        public void addHitModifierByArmor( int i )
        {
            _hitModifierByArmor += i;
        }

        private int _dmgModifierByArmor = 0; // 防具によるダメージ補正

        public int getDmgModifierByArmor()
        {
            return _dmgModifierByArmor;
        }

        public void addDmgModifierByArmor( int i )
        {
            _dmgModifierByArmor += i;
        }

        private int _bowHitModifierByArmor = 0; // 防具による弓の命中率補正

        public int getBowHitModifierByArmor()
        {
            return _bowHitModifierByArmor;
        }

        public void addBowHitModifierByArmor( int i )
        {
            _bowHitModifierByArmor += i;
        }

        private int _bowDmgModifierByArmor = 0; // 防具による弓のダメージ補正

        public int getBowDmgModifierByArmor()
        {
            return _bowDmgModifierByArmor;
        }

        public void addBowDmgModifierByArmor( int i )
        {
            _bowDmgModifierByArmor += i;
        }

        private bool _gresValid; // G-RESが有効か

        private void setGresValid( bool valid )
        {
            _gresValid = valid;
        }

        public bool isGresValid()
        {
            return _gresValid;
        }

        private long _fishingTime = 0;

        public long getFishingTime()
        {
            return _fishingTime;
        }

        public void setFishingTime( long i )
        {
            _fishingTime = i;
        }

        private bool _isFishing = false;

        public bool isFishing()
        {
            return _isFishing;
        }

        public void setFishing( bool flag )
        {
            _isFishing = flag;
        }

        private bool _isFishingReady = false;

        public bool isFishingReady()
        {
            return _isFishingReady;
        }

        public void setFishingReady( bool flag )
        {
            _isFishingReady = flag;
        }

        private int _cookingId = 0;

        public int getCookingId()
        {
            return _cookingId;
        }

        public void setCookingId( int i )
        {
            _cookingId = i;
        }

        private int _dessertId = 0;

        public int getDessertId()
        {
            return _dessertId;
        }

        public void setDessertId( int i )
        {
            _dessertId = i;
        }

        /// <summary>
        /// LVによる命中ボーナスを設定する LVが変動した場合などに呼び出せば再計算される。
        /// </summary>
        public void resetBaseDmgup()
        {
            int newBaseDmgup = 0;
            int newBaseBowDmgup = 0;
            if ( isKnight() || isDarkelf() || isDragonKnight() )
            { // ナイト、ダークエルフ、ドラゴンナイト
                newBaseDmgup = getLevel() / 10;
                newBaseBowDmgup = 0;
            }
            else if ( isElf() )
            { // エルフ
                newBaseDmgup = 0;
                newBaseBowDmgup = getLevel() / 10;
            }
            addDmgup( newBaseDmgup - _baseDmgup );
            addBowDmgup( newBaseBowDmgup - _baseBowDmgup );
            _baseDmgup = newBaseDmgup;
            _baseBowDmgup = newBaseBowDmgup;
        }

        /// <summary>
        /// LVによる命中ボーナスを設定する LVが変動した場合などに呼び出せば再計算される。
        /// </summary>
        public void resetBaseHitup()
        {
            int newBaseHitup = 0;
            int newBaseBowHitup = 0;
            if ( isCrown() )
            { // プリ
                newBaseHitup = getLevel() / 5;
                newBaseBowHitup = getLevel() / 5;
            }
            else if ( isKnight() )
            { // ナイト
                newBaseHitup = getLevel() / 3;
                newBaseBowHitup = getLevel() / 3;
            }
            else if ( isElf() )
            { // エルフ
                newBaseHitup = getLevel() / 5;
                newBaseBowHitup = getLevel() / 5;
            }
            else if ( isDarkelf() )
            { // ダークエルフ
                newBaseHitup = getLevel() / 3;
                newBaseBowHitup = getLevel() / 3;
            }
            else if ( isDragonKnight() )
            { // ドラゴンナイト
                newBaseHitup = getLevel() / 3;
                newBaseBowHitup = getLevel() / 3;
            }
            else if ( isIllusionist() )
            { // イリュージョニスト
                newBaseHitup = getLevel() / 5;
                newBaseBowHitup = getLevel() / 5;
            }
            addHitup( newBaseHitup - _baseHitup );
            addBowHitup( newBaseBowHitup - _baseBowHitup );
            _baseHitup = newBaseHitup;
            _baseBowHitup = newBaseBowHitup;
        }

        /// <summary>
        /// キャラクターステータスからACを再計算して設定する 初期設定時、LVUP,LVDown時などに呼び出す。
        /// </summary>
        public void resetBaseAc()
        {
            int newAc = CalcStat.calcAc( getLevel(), getBaseDex() );
            addAc( newAc - _baseAc );
            _baseAc = newAc;
        }

        /// <summary>
        /// キャラクターステータスから素のMRを再計算して設定する 初期設定時、スキル使用時やLVUP,LVDown時に呼び出す。
        /// </summary>
        public void resetBaseMr()
        {
            int newMr = 0;
            if ( isCrown() )
            { // プリ
                newMr = 10;
            }
            else if ( isElf() )
            { // エルフ
                newMr = 25;
            }
            else if ( isWizard() )
            { // ウィザード
                newMr = 15;
            }
            else if ( isDarkelf() )
            { // ダークエルフ
                newMr = 10;
            }
            else if ( isDragonKnight() )
            { // ドラゴンナイト
                newMr = 18;
            }
            else if ( isIllusionist() )
            { // イリュージョニスト
                newMr = 20;
            }
            newMr += CalcStat.calcStatMr( getWis() ); // WIS分のMRボーナス
            newMr += getLevel() / 2; // LVの半分だけ追加
            addMr( newMr - _baseMr );
            _baseMr = newMr;
        }

        /// <summary>
        /// EXPから現在のLvを再計算して設定する 初期設定時、死亡時やLVUP時に呼び出す。
        /// </summary>
        public void resetLevel()
        {
            setLevel( ExpTable.getLevelByExp( _exp ) );

            if ( _hpRegen != null )
            {
                _hpRegen.updateLevel();
            }
        }

        /// <summary>
        /// 初期ステータスから現在のボーナスを再計算して設定する 初期設定時、再配分時に呼び出す。
        /// </summary>
        public void resetOriginalHpup()
        {
            int originalCon = getOriginalCon();
            if ( isCrown() )
            {
                if ( originalCon == 12 || originalCon == 13 )
                {
                    _originalHpup = 1;
                }
                else if ( originalCon == 14 || originalCon == 15 )
                {
                    _originalHpup = 2;
                }
                else if ( originalCon >= 16 )
                {
                    _originalHpup = 3;
                }
                else
                {
                    _originalHpup = 0;
                }
            }
            else if ( isKnight() )
            {
                if ( originalCon == 15 || originalCon == 16 )
                {
                    _originalHpup = 1;
                }
                else if ( originalCon >= 17 )
                {
                    _originalHpup = 3;
                }
                else
                {
                    _originalHpup = 0;
                }
            }
            else if ( isElf() )
            {
                if ( originalCon >= 13 && originalCon <= 17 )
                {
                    _originalHpup = 1;
                }
                else if ( originalCon == 18 )
                {
                    _originalHpup = 2;
                }
                else
                {
                    _originalHpup = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalCon == 10 || originalCon == 11 )
                {
                    _originalHpup = 1;
                }
                else if ( originalCon >= 12 )
                {
                    _originalHpup = 2;
                }
                else
                {
                    _originalHpup = 0;
                }
            }
            else if ( isWizard() )
            {
                if ( originalCon == 14 || originalCon == 15 )
                {
                    _originalHpup = 1;
                }
                else if ( originalCon >= 16 )
                {
                    _originalHpup = 2;
                }
                else
                {
                    _originalHpup = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                if ( originalCon == 15 || originalCon == 16 )
                {
                    _originalHpup = 1;
                }
                else if ( originalCon >= 17 )
                {
                    _originalHpup = 3;
                }
                else
                {
                    _originalHpup = 0;
                }
            }
            else if ( isIllusionist() )
            {
                if ( originalCon == 13 || originalCon == 14 )
                {
                    _originalHpup = 1;
                }
                else if ( originalCon >= 15 )
                {
                    _originalHpup = 2;
                }
                else
                {
                    _originalHpup = 0;
                }
            }
        }

        public void resetOriginalMpup()
        {
            int originalWis = getOriginalWis();
            {
                if ( isCrown() )
                {
                    if ( originalWis >= 16 )
                    {
                        _originalMpup = 1;
                    }
                    else
                    {
                        _originalMpup = 0;
                    }
                }
                else if ( isKnight() )
                {
                    _originalMpup = 0;
                }
                else if ( isElf() )
                {
                    if ( originalWis >= 14 && originalWis <= 16 )
                    {
                        _originalMpup = 1;
                    }
                    else if ( originalWis >= 17 )
                    {
                        _originalMpup = 2;
                    }
                    else
                    {
                        _originalMpup = 0;
                    }
                }
                else if ( isDarkelf() )
                {
                    if ( originalWis >= 12 )
                    {
                        _originalMpup = 1;
                    }
                    else
                    {
                        _originalMpup = 0;
                    }
                }
                else if ( isWizard() )
                {
                    if ( originalWis >= 13 && originalWis <= 16 )
                    {
                        _originalMpup = 1;
                    }
                    else if ( originalWis >= 17 )
                    {
                        _originalMpup = 2;
                    }
                    else
                    {
                        _originalMpup = 0;
                    }
                }
                else if ( isDragonKnight() )
                {
                    if ( originalWis >= 13 && originalWis <= 15 )
                    {
                        _originalMpup = 1;
                    }
                    else if ( originalWis >= 16 )
                    {
                        _originalMpup = 2;
                    }
                    else
                    {
                        _originalMpup = 0;
                    }
                }
                else if ( isIllusionist() )
                {
                    if ( originalWis >= 13 && originalWis <= 15 )
                    {
                        _originalMpup = 1;
                    }
                    else if ( originalWis >= 16 )
                    {
                        _originalMpup = 2;
                    }
                    else
                    {
                        _originalMpup = 0;
                    }
                }
            }
        }

        public void resetOriginalStrWeightReduction()
        {
            int originalStr = getOriginalStr();
            if ( isCrown() )
            {
                if ( originalStr >= 14 && originalStr <= 16 )
                {
                    _originalStrWeightReduction = 1;
                }
                else if ( originalStr >= 17 && originalStr <= 19 )
                {
                    _originalStrWeightReduction = 2;
                }
                else if ( originalStr == 20 )
                {
                    _originalStrWeightReduction = 3;
                }
                else
                {
                    _originalStrWeightReduction = 0;
                }
            }
            else if ( isKnight() )
            {
                _originalStrWeightReduction = 0;
            }
            else if ( isElf() )
            {
                if ( originalStr >= 16 )
                {
                    _originalStrWeightReduction = 2;
                }
                else
                {
                    _originalStrWeightReduction = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalStr >= 13 && originalStr <= 15 )
                {
                    _originalStrWeightReduction = 2;
                }
                else if ( originalStr >= 16 )
                {
                    _originalStrWeightReduction = 3;
                }
                else
                {
                    _originalStrWeightReduction = 0;
                }
            }
            else if ( isWizard() )
            {
                if ( originalStr >= 9 )
                {
                    _originalStrWeightReduction = 1;
                }
                else
                {
                    _originalStrWeightReduction = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                if ( originalStr >= 16 )
                {
                    _originalStrWeightReduction = 1;
                }
                else
                {
                    _originalStrWeightReduction = 0;
                }
            }
            else if ( isIllusionist() )
            {
                if ( originalStr == 18 )
                {
                    _originalStrWeightReduction = 1;
                }
                else
                {
                    _originalStrWeightReduction = 0;
                }
            }
        }

        public void resetOriginalDmgup()
        {
            int originalStr = getOriginalStr();
            if ( isCrown() )
            {
                if ( originalStr >= 15 && originalStr <= 17 )
                {
                    _originalDmgup = 1;
                }
                else if ( originalStr >= 18 )
                {
                    _originalDmgup = 2;
                }
                else
                {
                    _originalDmgup = 0;
                }
            }
            else if ( isKnight() )
            {
                if ( originalStr == 18 || originalStr == 19 )
                {
                    _originalDmgup = 2;
                }
                else if ( originalStr == 20 )
                {
                    _originalDmgup = 4;
                }
                else
                {
                    _originalDmgup = 0;
                }
            }
            else if ( isElf() )
            {
                if ( originalStr == 12 || originalStr == 13 )
                {
                    _originalDmgup = 1;
                }
                else if ( originalStr >= 14 )
                {
                    _originalDmgup = 2;
                }
                else
                {
                    _originalDmgup = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalStr >= 14 && originalStr <= 17 )
                {
                    _originalDmgup = 1;
                }
                else if ( originalStr == 18 )
                {
                    _originalDmgup = 2;
                }
                else
                {
                    _originalDmgup = 0;
                }
            }
            else if ( isWizard() )
            {
                if ( originalStr == 10 || originalStr == 11 )
                {
                    _originalDmgup = 1;
                }
                else if ( originalStr >= 12 )
                {
                    _originalDmgup = 2;
                }
                else
                {
                    _originalDmgup = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                if ( originalStr >= 15 && originalStr <= 17 )
                {
                    _originalDmgup = 1;
                }
                else if ( originalStr >= 18 )
                {
                    _originalDmgup = 3;
                }
                else
                {
                    _originalDmgup = 0;
                }
            }
            else if ( isIllusionist() )
            {
                if ( originalStr == 13 || originalStr == 14 )
                {
                    _originalDmgup = 1;
                }
                else if ( originalStr >= 15 )
                {
                    _originalDmgup = 2;
                }
                else
                {
                    _originalDmgup = 0;
                }
            }
        }

        public void resetOriginalConWeightReduction()
        {
            int originalCon = getOriginalCon();
            if ( isCrown() )
            {
                if ( originalCon >= 11 )
                {
                    _originalConWeightReduction = 1;
                }
                else
                {
                    _originalConWeightReduction = 0;
                }
            }
            else if ( isKnight() )
            {
                if ( originalCon >= 15 )
                {
                    _originalConWeightReduction = 1;
                }
                else
                {
                    _originalConWeightReduction = 0;
                }
            }
            else if ( isElf() )
            {
                if ( originalCon >= 15 )
                {
                    _originalConWeightReduction = 2;
                }
                else
                {
                    _originalConWeightReduction = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalCon >= 9 )
                {
                    _originalConWeightReduction = 1;
                }
                else
                {
                    _originalConWeightReduction = 0;
                }
            }
            else if ( isWizard() )
            {
                if ( originalCon == 13 || originalCon == 14 )
                {
                    _originalConWeightReduction = 1;
                }
                else if ( originalCon >= 15 )
                {
                    _originalConWeightReduction = 2;
                }
                else
                {
                    _originalConWeightReduction = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                _originalConWeightReduction = 0;
            }
            else if ( isIllusionist() )
            {
                if ( originalCon == 17 )
                {
                    _originalConWeightReduction = 1;
                }
                else if ( originalCon == 18 )
                {
                    _originalConWeightReduction = 2;
                }
                else
                {
                    _originalConWeightReduction = 0;
                }
            }
        }

        public void resetOriginalBowDmgup()
        {
            int originalDex = getOriginalDex();
            if ( isCrown() )
            {
                if ( originalDex >= 13 )
                {
                    _originalBowDmgup = 1;
                }
                else
                {
                    _originalBowDmgup = 0;
                }
            }
            else if ( isKnight() )
            {
                _originalBowDmgup = 0;
            }
            else if ( isElf() )
            {
                if ( originalDex >= 14 && originalDex <= 16 )
                {
                    _originalBowDmgup = 2;
                }
                else if ( originalDex >= 17 )
                {
                    _originalBowDmgup = 3;
                }
                else
                {
                    _originalBowDmgup = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalDex == 18 )
                {
                    _originalBowDmgup = 2;
                }
                else
                {
                    _originalBowDmgup = 0;
                }
            }
            else if ( isWizard() )
            {
                _originalBowDmgup = 0;
            }
            else if ( isDragonKnight() )
            {
                _originalBowDmgup = 0;
            }
            else if ( isIllusionist() )
            {
                _originalBowDmgup = 0;
            }
        }

        public void resetOriginalHitup()
        {
            int originalStr = getOriginalStr();
            if ( isCrown() )
            {
                if ( originalStr >= 16 && originalStr <= 18 )
                {
                    _originalHitup = 1;
                }
                else if ( originalStr >= 19 )
                {
                    _originalHitup = 2;
                }
                else
                {
                    _originalHitup = 0;
                }
            }
            else if ( isKnight() )
            {
                if ( originalStr == 17 || originalStr == 18 )
                {
                    _originalHitup = 2;
                }
                else if ( originalStr >= 19 )
                {
                    _originalHitup = 4;
                }
                else
                {
                    _originalHitup = 0;
                }
            }
            else if ( isElf() )
            {
                if ( originalStr == 13 || originalStr == 14 )
                {
                    _originalHitup = 1;
                }
                else if ( originalStr >= 15 )
                {
                    _originalHitup = 2;
                }
                else
                {
                    _originalHitup = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalStr >= 15 && originalStr <= 17 )
                {
                    _originalHitup = 1;
                }
                else if ( originalStr == 18 )
                {
                    _originalHitup = 2;
                }
                else
                {
                    _originalHitup = 0;
                }
            }
            else if ( isWizard() )
            {
                if ( originalStr == 11 || originalStr == 12 )
                {
                    _originalHitup = 1;
                }
                else if ( originalStr >= 13 )
                {
                    _originalHitup = 2;
                }
                else
                {
                    _originalHitup = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                if ( originalStr >= 14 && originalStr <= 16 )
                {
                    _originalHitup = 1;
                }
                else if ( originalStr >= 17 )
                {
                    _originalHitup = 3;
                }
                else
                {
                    _originalHitup = 0;
                }
            }
            else if ( isIllusionist() )
            {
                if ( originalStr == 12 || originalStr == 13 )
                {
                    _originalHitup = 1;
                }
                else if ( originalStr == 14 || originalStr == 15 )
                {
                    _originalHitup = 2;
                }
                else if ( originalStr == 16 )
                {
                    _originalHitup = 3;
                }
                else if ( originalStr >= 17 )
                {
                    _originalHitup = 4;
                }
                else
                {
                    _originalHitup = 0;
                }
            }
        }

        public void resetOriginalBowHitup()
        {
            int originalDex = getOriginalDex();
            if ( isCrown() )
            {
                _originalBowHitup = 0;
            }
            else if ( isKnight() )
            {
                _originalBowHitup = 0;
            }
            else if ( isElf() )
            {
                if ( originalDex >= 13 && originalDex <= 15 )
                {
                    _originalBowHitup = 2;
                }
                else if ( originalDex >= 16 )
                {
                    _originalBowHitup = 3;
                }
                else
                {
                    _originalBowHitup = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalDex == 17 )
                {
                    _originalBowHitup = 1;
                }
                else if ( originalDex == 18 )
                {
                    _originalBowHitup = 2;
                }
                else
                {
                    _originalBowHitup = 0;
                }
            }
            else if ( isWizard() )
            {
                _originalBowHitup = 0;
            }
            else if ( isDragonKnight() )
            {
                _originalBowHitup = 0;
            }
            else if ( isIllusionist() )
            {
                _originalBowHitup = 0;
            }
        }

        public void resetOriginalMr()
        {
            int originalWis = getOriginalWis();
            if ( isCrown() )
            {
                if ( originalWis == 12 || originalWis == 13 )
                {
                    _originalMr = 1;
                }
                else if ( originalWis >= 14 )
                {
                    _originalMr = 2;
                }
                else
                {
                    _originalMr = 0;
                }
            }
            else if ( isKnight() )
            {
                if ( originalWis == 10 || originalWis == 11 )
                {
                    _originalMr = 1;
                }
                else if ( originalWis >= 12 )
                {
                    _originalMr = 2;
                }
                else
                {
                    _originalMr = 0;
                }
            }
            else if ( isElf() )
            {
                if ( originalWis >= 13 && originalWis <= 15 )
                {
                    _originalMr = 1;
                }
                else if ( originalWis >= 16 )
                {
                    _originalMr = 2;
                }
                else
                {
                    _originalMr = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalWis >= 11 && originalWis <= 13 )
                {
                    _originalMr = 1;
                }
                else if ( originalWis == 14 )
                {
                    _originalMr = 2;
                }
                else if ( originalWis == 15 )
                {
                    _originalMr = 3;
                }
                else if ( originalWis >= 16 )
                {
                    _originalMr = 4;
                }
                else
                {
                    _originalMr = 0;
                }
            }
            else if ( isWizard() )
            {
                if ( originalWis >= 15 )
                {
                    _originalMr = 1;
                }
                else
                {
                    _originalMr = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                if ( originalWis >= 14 )
                {
                    _originalMr = 2;
                }
                else
                {
                    _originalMr = 0;
                }
            }
            else if ( isIllusionist() )
            {
                if ( originalWis >= 15 && originalWis <= 17 )
                {
                    _originalMr = 2;
                }
                else if ( originalWis == 18 )
                {
                    _originalMr = 4;
                }
                else
                {
                    _originalMr = 0;
                }
            }

            addMr( _originalMr );
        }

        public void resetOriginalMagicHit()
        {
            int originalInt = getOriginalInt();
            if ( isCrown() )
            {
                if ( originalInt == 12 || originalInt == 13 )
                {
                    _originalMagicHit = 1;
                }
                else if ( originalInt >= 14 )
                {
                    _originalMagicHit = 2;
                }
                else
                {
                    _originalMagicHit = 0;
                }
            }
            else if ( isKnight() )
            {
                if ( originalInt == 10 || originalInt == 11 )
                {
                    _originalMagicHit = 1;
                }
                else if ( originalInt == 12 )
                {
                    _originalMagicHit = 2;
                }
                else
                {
                    _originalMagicHit = 0;
                }
            }
            else if ( isElf() )
            {
                if ( originalInt == 13 || originalInt == 14 )
                {
                    _originalMagicHit = 1;
                }
                else if ( originalInt >= 15 )
                {
                    _originalMagicHit = 2;
                }
                else
                {
                    _originalMagicHit = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalInt == 12 || originalInt == 13 )
                {
                    _originalMagicHit = 1;
                }
                else if ( originalInt >= 14 )
                {
                    _originalMagicHit = 2;
                }
                else
                {
                    _originalMagicHit = 0;
                }
            }
            else if ( isWizard() )
            {
                if ( originalInt >= 14 )
                {
                    _originalMagicHit = 1;
                }
                else
                {
                    _originalMagicHit = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                if ( originalInt == 12 || originalInt == 13 )
                {
                    _originalMagicHit = 2;
                }
                else if ( originalInt == 14 || originalInt == 15 )
                {
                    _originalMagicHit = 3;
                }
                else if ( originalInt >= 16 )
                {
                    _originalMagicHit = 4;
                }
                else
                {
                    _originalMagicHit = 0;
                }
            }
            else if ( isIllusionist() )
            {
                if ( originalInt >= 13 )
                {
                    _originalMagicHit = 1;
                }
                else
                {
                    _originalMagicHit = 0;
                }
            }
        }

        public void resetOriginalMagicCritical()
        {
            int originalInt = getOriginalInt();
            if ( isCrown() )
            {
                _originalMagicCritical = 0;
            }
            else if ( isKnight() )
            {
                _originalMagicCritical = 0;
            }
            else if ( isElf() )
            {
                if ( originalInt == 14 || originalInt == 15 )
                {
                    _originalMagicCritical = 2;
                }
                else if ( originalInt >= 16 )
                {
                    _originalMagicCritical = 4;
                }
                else
                {
                    _originalMagicCritical = 0;
                }
            }
            else if ( isDarkelf() )
            {
                _originalMagicCritical = 0;
            }
            else if ( isWizard() )
            {
                if ( originalInt == 15 )
                {
                    _originalMagicCritical = 2;
                }
                else if ( originalInt == 16 )
                {
                    _originalMagicCritical = 4;
                }
                else if ( originalInt == 17 )
                {
                    _originalMagicCritical = 6;
                }
                else if ( originalInt == 18 )
                {
                    _originalMagicCritical = 8;
                }
                else
                {
                    _originalMagicCritical = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                _originalMagicCritical = 0;
            }
            else if ( isIllusionist() )
            {
                _originalMagicCritical = 0;
            }
        }

        public void resetOriginalMagicConsumeReduction()
        {
            int originalInt = getOriginalInt();
            if ( isCrown() )
            {
                if ( originalInt == 11 || originalInt == 12 )
                {
                    _originalMagicConsumeReduction = 1;
                }
                else if ( originalInt >= 13 )
                {
                    _originalMagicConsumeReduction = 2;
                }
                else
                {
                    _originalMagicConsumeReduction = 0;
                }
            }
            else if ( isKnight() )
            {
                if ( originalInt == 9 || originalInt == 10 )
                {
                    _originalMagicConsumeReduction = 1;
                }
                else if ( originalInt >= 11 )
                {
                    _originalMagicConsumeReduction = 2;
                }
                else
                {
                    _originalMagicConsumeReduction = 0;
                }
            }
            else if ( isElf() )
            {
                _originalMagicConsumeReduction = 0;
            }
            else if ( isDarkelf() )
            {
                if ( originalInt == 13 || originalInt == 14 )
                {
                    _originalMagicConsumeReduction = 1;
                }
                else if ( originalInt >= 15 )
                {
                    _originalMagicConsumeReduction = 2;
                }
                else
                {
                    _originalMagicConsumeReduction = 0;
                }
            }
            else if ( isWizard() )
            {
                _originalMagicConsumeReduction = 0;
            }
            else if ( isDragonKnight() )
            {
                _originalMagicConsumeReduction = 0;
            }
            else if ( isIllusionist() )
            {
                if ( originalInt == 14 )
                {
                    _originalMagicConsumeReduction = 1;
                }
                else if ( originalInt >= 15 )
                {
                    _originalMagicConsumeReduction = 2;
                }
                else
                {
                    _originalMagicConsumeReduction = 0;
                }
            }
        }

        public void resetOriginalMagicDamage()
        {
            int originalInt = getOriginalInt();
            if ( isCrown() )
            {
                _originalMagicDamage = 0;
            }
            else if ( isKnight() )
            {
                _originalMagicDamage = 0;
            }
            else if ( isElf() )
            {
                _originalMagicDamage = 0;
            }
            else if ( isDarkelf() )
            {
                _originalMagicDamage = 0;
            }
            else if ( isWizard() )
            {
                if ( originalInt >= 13 )
                {
                    _originalMagicDamage = 1;
                }
                else
                {
                    _originalMagicDamage = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                if ( originalInt == 13 || originalInt == 14 )
                {
                    _originalMagicDamage = 1;
                }
                else if ( originalInt == 15 || originalInt == 16 )
                {
                    _originalMagicDamage = 2;
                }
                else if ( originalInt == 17 )
                {
                    _originalMagicDamage = 3;
                }
                else
                {
                    _originalMagicDamage = 0;
                }
            }
            else if ( isIllusionist() )
            {
                if ( originalInt == 16 )
                {
                    _originalMagicDamage = 1;
                }
                else if ( originalInt == 17 )
                {
                    _originalMagicDamage = 2;
                }
                else
                {
                    _originalMagicDamage = 0;
                }
            }
        }

        public void resetOriginalAc()
        {
            int originalDex = getOriginalDex();
            if ( isCrown() )
            {
                if ( originalDex >= 12 && originalDex <= 14 )
                {
                    _originalAc = 1;
                }
                else if ( originalDex == 15 || originalDex == 16 )
                {
                    _originalAc = 2;
                }
                else if ( originalDex >= 17 )
                {
                    _originalAc = 3;
                }
                else
                {
                    _originalAc = 0;
                }
            }
            else if ( isKnight() )
            {
                if ( originalDex == 13 || originalDex == 14 )
                {
                    _originalAc = 1;
                }
                else if ( originalDex >= 15 )
                {
                    _originalAc = 3;
                }
                else
                {
                    _originalAc = 0;
                }
            }
            else if ( isElf() )
            {
                if ( originalDex >= 15 && originalDex <= 17 )
                {
                    _originalAc = 1;
                }
                else if ( originalDex == 18 )
                {
                    _originalAc = 2;
                }
                else
                {
                    _originalAc = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalDex >= 17 )
                {
                    _originalAc = 1;
                }
                else
                {
                    _originalAc = 0;
                }
            }
            else if ( isWizard() )
            {
                if ( originalDex == 8 || originalDex == 9 )
                {
                    _originalAc = 1;
                }
                else if ( originalDex >= 10 )
                {
                    _originalAc = 2;
                }
                else
                {
                    _originalAc = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                if ( originalDex == 12 || originalDex == 13 )
                {
                    _originalAc = 1;
                }
                else if ( originalDex >= 14 )
                {
                    _originalAc = 2;
                }
                else
                {
                    _originalAc = 0;
                }
            }
            else if ( isIllusionist() )
            {
                if ( originalDex == 11 || originalDex == 12 )
                {
                    _originalAc = 1;
                }
                else if ( originalDex >= 13 )
                {
                    _originalAc = 2;
                }
                else
                {
                    _originalAc = 0;
                }
            }

            addAc( 0 - _originalAc );
        }

        public void resetOriginalEr()
        {
            int originalDex = getOriginalDex();
            if ( isCrown() )
            {
                if ( originalDex == 14 || originalDex == 15 )
                {
                    _originalEr = 1;
                }
                else if ( originalDex == 16 || originalDex == 17 )
                {
                    _originalEr = 2;
                }
                else if ( originalDex == 18 )
                {
                    _originalEr = 3;
                }
                else
                {
                    _originalEr = 0;
                }
            }
            else if ( isKnight() )
            {
                if ( originalDex == 14 || originalDex == 15 )
                {
                    _originalEr = 1;
                }
                else if ( originalDex == 16 )
                {
                    _originalEr = 3;
                }
                else
                {
                    _originalEr = 0;
                }
            }
            else if ( isElf() )
            {
                _originalEr = 0;
            }
            else if ( isDarkelf() )
            {
                if ( originalDex >= 16 )
                {
                    _originalEr = 2;
                }
                else
                {
                    _originalEr = 0;
                }
            }
            else if ( isWizard() )
            {
                if ( originalDex == 9 || originalDex == 10 )
                {
                    _originalEr = 1;
                }
                else if ( originalDex == 11 )
                {
                    _originalEr = 2;
                }
                else
                {
                    _originalEr = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                if ( originalDex == 13 || originalDex == 14 )
                {
                    _originalEr = 1;
                }
                else if ( originalDex >= 15 )
                {
                    _originalEr = 2;
                }
                else
                {
                    _originalEr = 0;
                }
            }
            else if ( isIllusionist() )
            {
                if ( originalDex == 12 || originalDex == 13 )
                {
                    _originalEr = 1;
                }
                else if ( originalDex >= 14 )
                {
                    _originalEr = 2;
                }
                else
                {
                    _originalEr = 0;
                }
            }
        }

        public void resetOriginalHpr()
        {
            int originalCon = getOriginalCon();
            if ( isCrown() )
            {
                if ( originalCon == 13 || originalCon == 14 )
                {
                    _originalHpr = 1;
                }
                else if ( originalCon == 15 || originalCon == 16 )
                {
                    _originalHpr = 2;
                }
                else if ( originalCon == 17 )
                {
                    _originalHpr = 3;
                }
                else if ( originalCon == 18 )
                {
                    _originalHpr = 4;
                }
                else
                {
                    _originalHpr = 0;
                }
            }
            else if ( isKnight() )
            {
                if ( originalCon == 16 || originalCon == 17 )
                {
                    _originalHpr = 2;
                }
                else if ( originalCon == 18 )
                {
                    _originalHpr = 4;
                }
                else
                {
                    _originalHpr = 0;
                }
            }
            else if ( isElf() )
            {
                if ( originalCon == 14 || originalCon == 15 )
                {
                    _originalHpr = 1;
                }
                else if ( originalCon == 16 )
                {
                    _originalHpr = 2;
                }
                else if ( originalCon >= 17 )
                {
                    _originalHpr = 3;
                }
                else
                {
                    _originalHpr = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalCon == 11 || originalCon == 12 )
                {
                    _originalHpr = 1;
                }
                else if ( originalCon >= 13 )
                {
                    _originalHpr = 2;
                }
                else
                {
                    _originalHpr = 0;
                }
            }
            else if ( isWizard() )
            {
                if ( originalCon == 17 )
                {
                    _originalHpr = 1;
                }
                else if ( originalCon == 18 )
                {
                    _originalHpr = 2;
                }
                else
                {
                    _originalHpr = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                if ( originalCon == 16 || originalCon == 17 )
                {
                    _originalHpr = 1;
                }
                else if ( originalCon == 18 )
                {
                    _originalHpr = 3;
                }
                else
                {
                    _originalHpr = 0;
                }
            }
            else if ( isIllusionist() )
            {
                if ( originalCon == 14 || originalCon == 15 )
                {
                    _originalHpr = 1;
                }
                else if ( originalCon >= 16 )
                {
                    _originalHpr = 2;
                }
                else
                {
                    _originalHpr = 0;
                }
            }
        }

        public void resetOriginalMpr()
        {
            int originalWis = getOriginalWis();
            if ( isCrown() )
            {
                if ( originalWis == 13 || originalWis == 14 )
                {
                    _originalMpr = 1;
                }
                else if ( originalWis >= 15 )
                {
                    _originalMpr = 2;
                }
                else
                {
                    _originalMpr = 0;
                }
            }
            else if ( isKnight() )
            {
                if ( originalWis == 11 || originalWis == 12 )
                {
                    _originalMpr = 1;
                }
                else if ( originalWis == 13 )
                {
                    _originalMpr = 2;
                }
                else
                {
                    _originalMpr = 0;
                }
            }
            else if ( isElf() )
            {
                if ( originalWis >= 15 && originalWis <= 17 )
                {
                    _originalMpr = 1;
                }
                else if ( originalWis == 18 )
                {
                    _originalMpr = 2;
                }
                else
                {
                    _originalMpr = 0;
                }
            }
            else if ( isDarkelf() )
            {
                if ( originalWis >= 13 )
                {
                    _originalMpr = 1;
                }
                else
                {
                    _originalMpr = 0;
                }
            }
            else if ( isWizard() )
            {
                if ( originalWis == 14 || originalWis == 15 )
                {
                    _originalMpr = 1;
                }
                else if ( originalWis == 16 || originalWis == 17 )
                {
                    _originalMpr = 2;
                }
                else if ( originalWis == 18 )
                {
                    _originalMpr = 3;
                }
                else
                {
                    _originalMpr = 0;
                }
            }
            else if ( isDragonKnight() )
            {
                if ( originalWis == 15 || originalWis == 16 )
                {
                    _originalMpr = 1;
                }
                else if ( originalWis >= 17 )
                {
                    _originalMpr = 2;
                }
                else
                {
                    _originalMpr = 0;
                }
            }
            else if ( isIllusionist() )
            {
                if ( originalWis >= 14 && originalWis <= 16 )
                {
                    _originalMpr = 1;
                }
                else if ( originalWis >= 17 )
                {
                    _originalMpr = 2;
                }
                else
                {
                    _originalMpr = 0;
                }
            }
        }

        public void refresh()
        {
            resetLevel();
            resetBaseHitup();
            resetBaseDmgup();
            resetBaseMr();
            resetBaseAc();
            resetOriginalHpup();
            resetOriginalMpup();
            resetOriginalDmgup();
            resetOriginalBowDmgup();
            resetOriginalHitup();
            resetOriginalBowHitup();
            resetOriginalMr();
            resetOriginalMagicHit();
            resetOriginalMagicCritical();
            resetOriginalMagicConsumeReduction();
            resetOriginalMagicDamage();
            resetOriginalAc();
            resetOriginalEr();
            resetOriginalHpr();
            resetOriginalMpr();
            resetOriginalStrWeightReduction();
            resetOriginalConWeightReduction();
        }

        private L1ExcludingList _excludingList = new L1ExcludingList();

        public L1ExcludingList getExcludingList()
        {
            return _excludingList;
        }

        // -- 加速器検知機能 --
        private AcceleratorChecker _acceleratorChecker = new AcceleratorChecker();

        public AcceleratorChecker getAcceleratorChecker()
        {
            return _acceleratorChecker;
        }

        /// <summary>
        /// テレポート先の座標
        /// </summary>
        private int _teleportX = 0;

        public int getTeleportX()
        {
            return _teleportX;
        }

        public void setTeleportX( int i )
        {
            _teleportX = i;
        }

        private int _teleportY = 0;

        public int getTeleportY()
        {
            return _teleportY;
        }

        public void setTeleportY( int i )
        {
            _teleportY = i;
        }

        private short _teleportMapId = 0;

        public short getTeleportMapId()
        {
            return _teleportMapId;
        }

        public void setTeleportMapId( short i )
        {
            _teleportMapId = i;
        }

        private int _teleportHeading = 0;

        public int getTeleportHeading()
        {
            return _teleportHeading;
        }

        public void setTeleportHeading( int i )
        {
            _teleportHeading = i;
        }

        private int _tempCharGfxAtDead;

        public int getTempCharGfxAtDead()
        {
            return _tempCharGfxAtDead;
        }

        public void setTempCharGfxAtDead( int i )
        {
            _tempCharGfxAtDead = i;
        }

        private bool _isCanWhisper = true;

        public bool isCanWhisper()
        {
            return _isCanWhisper;
        }

        public void setCanWhisper( bool flag )
        {
            _isCanWhisper = flag;
        }

        private bool _isShowTradeChat = true;

        public bool isShowTradeChat()
        {
            return _isShowTradeChat;
        }

        public void setShowTradeChat( bool flag )
        {
            _isShowTradeChat = flag;
        }

        private bool _isShowWorldChat = true;

        public bool isShowWorldChat()
        {
            return _isShowWorldChat;
        }

        public void setShowWorldChat( bool flag )
        {
            _isShowWorldChat = flag;
        }

        private int _fightId;

        public int getFightId()
        {
            return _fightId;
        }

        public void setFightId( int i )
        {
            _fightId = i;
        }

        private byte _chatCount = 0;

        private long _oldChatTimeInMillis = 0L;

        public void checkChatInterval()
        {
            long nowChatTimeInMillis = DateTime.Today.Ticks / 10000;
            if ( _chatCount == 0 )
            {
                _chatCount++;
                _oldChatTimeInMillis = nowChatTimeInMillis;
                return;
            }

            long chatInterval = nowChatTimeInMillis - _oldChatTimeInMillis;
            if ( chatInterval > 2000 )
            {
                _chatCount = 0;
                _oldChatTimeInMillis = 0;
            }
            else
            {
                if ( _chatCount >= 3 )
                {
                    setSkillEffect( L1SkillId.STATUS_CHAT_PROHIBITED, 120 * 1000 );
                    sendPackets( new S_SkillIconGFX( 36, 120 ) );
                    sendPackets( new S_ServerMessage( 153 ) ); // \f3迷惑なチャット流しをしたので、今後2分間チャットを行うことはできません。
                    _chatCount = 0;
                    _oldChatTimeInMillis = 0;
                }
                _chatCount++;
            }
        }

        private int _callClanId;

        public int getCallClanId()
        {
            return _callClanId;
        }

        public void setCallClanId( int i )
        {
            _callClanId = i;
        }

        private int _callClanHeading;

        public int getCallClanHeading()
        {
            return _callClanHeading;
        }

        public void setCallClanHeading( int i )
        {
            _callClanHeading = i;
        }

        private bool _isInCharReset = false;

        public bool isInCharReset()
        {
            return _isInCharReset;
        }

        public void setInCharReset( bool flag )
        {
            _isInCharReset = flag;
        }

        private int _tempLevel = 1;

        public int getTempLevel()
        {
            return _tempLevel;
        }

        public void setTempLevel( int i )
        {
            _tempLevel = i;
        }

        private int _tempMaxLevel = 1;

        public int getTempMaxLevel()
        {
            return _tempMaxLevel;
        }

        public void setTempMaxLevel( int i )
        {
            _tempMaxLevel = i;
        }

        private int _awakeSkillId = 0;

        public int getAwakeSkillId()
        {
            return _awakeSkillId;
        }

        public void setAwakeSkillId( int i )
        {
            _awakeSkillId = i;
        }

        private bool _isSummonMonster = false;

        public void setSummonMonster( bool SummonMonster )
        {
            _isSummonMonster = SummonMonster;
        }

        public bool isSummonMonster()
        {
            return _isSummonMonster;
        }

        private bool _isShapeChange = false;

        public void setShapeChange( bool isShapeChange )
        {
            _isShapeChange = isShapeChange;
        }

        public bool isShapeChange()
        {
            return _isShapeChange;
        }
    }
}
